Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2008, Unitils.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.unitils.inject.util;
import ognl.DefaultMemberAccess;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.unitils.core.UnitilsException;
import org.unitils.util.AnnotationUtils;
import org.unitils.util.ReflectionUtils;
import static org.unitils.util.ReflectionUtils.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Set;
/**
* Class containing static methods that implement explicit injection using OGNL expressions, and auto-injection by type.
*
* @author Filip Neven
* @author Tim Ducheyne
*/
public class InjectionUtils {
/* The logger instance for this class */
private static Log logger = LogFactory.getLog(InjectionUtils.class);
/**
* Explicit injection of the objectToInject into the specified property of the target. The property should be a
* correct OGNL expression.
*
* @param objectToInject The object that is injected
* @param target The target object
* @param property The OGNL expression that defines where the object will be injected, not null
* @return The object that was replaced by the injection
*/
public static Object injectInto(Object objectToInject, Object target, String property) {
if (target == null) {
throw new UnitilsException("Target for injection should not be null");
}
try {
OgnlContext ognlContext = new OgnlContext();
ognlContext.setMemberAccess(new DefaultMemberAccess(true));
Object ognlExpression = Ognl.parseExpression(property);
Object oldValue = null;
try {
Ognl.getValue(ognlExpression, ognlContext, target);
} catch (Exception e) {
logger.warn("Unable to retrieve current value of field to inject into. Will not be able to restore value after injection.", e);
}
Ognl.setValue(ognlExpression, ognlContext, target, objectToInject);
return oldValue;
} catch (OgnlException e) {
throw new UnitilsException("Failed to set value using OGNL expression " + property, e);
}
}
/**
* Explicit injection of the objectToInject into the specified static property of the target class. The property
* should be a correct OGNL expression.
*
* @param objectToInject The object that is injected
* @param targetClass The target class, not null
* @param property The OGNL expression that defines where the object will be injected, not null
* @return The object that was replaced by the injection
*/
public static Object injectIntoStatic(Object objectToInject, Class> targetClass, String property) {
String staticProperty = StringUtils.substringBefore(property, ".");
if (property.equals(staticProperty)) {
// Simple property: directly set value on this property
Object oldValue = null;
try {
oldValue = getValueStatic(targetClass, staticProperty);
} catch (Exception e) {
logger.warn("Unable to retrieve current value of field to inject into. Will not be able to restore value after injection.", e);
}
setValueStatic(targetClass, staticProperty, objectToInject);
return oldValue;
} else {
// Multipart property: use ognl for remaining property part
Object objectToInjectInto = getValueStatic(targetClass, staticProperty);
String remainingPropertyPart = StringUtils.substringAfter(property, ".");
try {
return injectInto(objectToInject, objectToInjectInto, remainingPropertyPart);
} catch (UnitilsException e) {
throw new UnitilsException("Property named " + remainingPropertyPart + " not found on " + objectToInjectInto.getClass().getSimpleName(), e);
}
}
}
/**
* Performs auto-injection by type of the objectToInject on the target object.
*
* @param objectToInject The object that is injected
* @param objectToInjectType The type of the object. This should be the type of the object or one of his super-types
* or implemented interfaces. This type is used for property type matching on the target object
* @param target The object into which the objectToInject is injected
* @param propertyAccess Defines if field or setter injection is used
* @return The object that was replaced by the injection
*/
public static Object injectIntoByType(Object objectToInject, Type objectToInjectType, Object target, PropertyAccess propertyAccess) {
if (target == null) {
throw new UnitilsException("Target for injection should not be null");
}
if (propertyAccess == PropertyAccess.FIELD) {
return injectIntoFieldByType(objectToInject, objectToInjectType, target, target.getClass(), false);
}
return injectIntoSetterByType(objectToInject, objectToInjectType, target, target.getClass(), false);
}
/**
* Performs auto-injection by type of the objectToInject into the target class.
*
* @param objectToInject The object that is injected
* @param objectToInjectType The type of the object. This should be the type of the object or one of his super-types
* or implemented interfaces. This type is used for property type matching on the target class
* @param targetClass The class into which the objectToInject is injected
* @param propertyAccess Defines if field or setter injection is used
* @return The object that was replaced by the injection
*/
public static Object injectIntoStaticByType(Object objectToInject, Type objectToInjectType, Class> targetClass, PropertyAccess propertyAccess) {
if (propertyAccess == PropertyAccess.FIELD) {
return injectIntoFieldByType(objectToInject, objectToInjectType, null, targetClass, true);
}
return injectIntoSetterByType(objectToInject, objectToInjectType, null, targetClass, true);
}
public static void injectIntoAnnotated(Object objectToInject, Object target, Class extends Annotation> annotation) {
injectIntoAnnotatedFields(objectToInject, target, annotation);
injectIntoAnnotatedMethods(objectToInject, target, annotation);
}
public static void injectIntoAnnotatedMethods(Object objectToInject, Object target, Class extends Annotation> annotation) {
Set annotatedMethods = AnnotationUtils.getMethodsAnnotatedWith(target.getClass(), annotation);
for (Method annotatedMethod : annotatedMethods) {
try {
annotatedMethod.invoke(target, objectToInject);
} catch (IllegalArgumentException e) {
throw new UnitilsException("Method " + annotatedMethod.getName() + " annotated with " + annotation.getName() + " must have exactly one argument with a type equal to or a superclass / implemented interface of " + objectToInject.getClass().getSimpleName());
} catch (IllegalAccessException e) {
throw new UnitilsException("Unable to inject value into following method annotated with " + annotation.getName() + ": " + annotatedMethod.getName(), e);
} catch (InvocationTargetException e) {
throw new UnitilsException("Unable to inject value into following method annotated with " + annotation.getName() + ": " + annotatedMethod.getName(), e);
}
}
}
public static void injectIntoAnnotatedFields(Object objectToInject, Object target, Class extends Annotation> annotation) {
Set annotatedFields = AnnotationUtils.getFieldsAnnotatedWith(target.getClass(), annotation);
for (Field annotatedField : annotatedFields) {
setFieldValue(target, annotatedField, objectToInject);
}
}
/**
* Performs auto-injection on a field by type of the objectToInject into the given target object or targetClass,
* depending on the value of isStatic. The object is injected on one single field, if there is more than one
* candidate field, a {@link UnitilsException} is thrown. We try to inject the object on the most specific field,
* this means that when there are muliple fields of one of the super-types or implemented interfaces of the field,
* the one that is lowest in the hierarchy is chosen (if possible, otherwise, a {@link UnitilsException} is thrown.
*
* @param objectToInject The object that is injected
* @param objectToInjectType The type of the object that is injected
* @param target The target object (only used when isStatic is false)
* @param targetClass The target class (only used when isStatis is true)
* @param isStatic Indicates wether injection should be performed on the target object or on the target class
* @return The object that was replaced by the injection
*/
private static Object injectIntoFieldByType(Object objectToInject, Type objectToInjectType, Object target, Class> targetClass, boolean isStatic) {
// Try to find a field with an exact matching type
Field fieldToInjectTo = null;
Set fieldsWithExactType = getFieldsOfType(targetClass, objectToInjectType, isStatic);
if (fieldsWithExactType.size() > 1) {
StringBuilder message = new StringBuilder("More than one " + (isStatic ? "static " : "") + "field with type " + objectToInjectType + " found in " + targetClass.getSimpleName() + ".");
if (objectToInjectType instanceof Class>) {
message.append(" If the target is a generic type, this can be caused by type erasure.");
}
message.append(" Specify the target field explicitly instead of injecting into by type.");
throw new UnitilsException(message.toString());
} else if (fieldsWithExactType.size() == 1) {
fieldToInjectTo = fieldsWithExactType.iterator().next();
} else {
// Try to find a supertype field:
// If one field exist that has a type which is more specific than all other fields of the given type,
// this one is taken. Otherwise, an exception is thrown
Set fieldsOfType = getFieldsAssignableFrom(targetClass, objectToInjectType, isStatic);
if (fieldsOfType.size() == 0) {
throw new UnitilsException("No " + (isStatic ? "static " : "") + "field with (super)type " + objectToInjectType + " found in " + targetClass.getSimpleName());
}
for (Field field : fieldsOfType) {
boolean moreSpecific = true;
for (Field compareToField : fieldsOfType) {
if (field != compareToField) {
if (field.getClass().isAssignableFrom(compareToField.getClass())) {
moreSpecific = false;
break;
}
}
}
if (moreSpecific) {
fieldToInjectTo = field;
break;
}
}
if (fieldToInjectTo == null) {
throw new UnitilsException("Multiple candidate target " + (isStatic ? "static " : "") + "fields found in " + targetClass.getSimpleName() + ", with none of them more specific than all others.");
}
}
// Field to inject into found, inject the object and return old value
Object oldValue = null;
try {
oldValue = getFieldValue(target, fieldToInjectTo);
} catch (Exception e) {
logger.warn("Unable to retrieve current value of field to inject into. Will not be able to restore value after injection.", e);
}
setFieldValue(target, fieldToInjectTo, objectToInject);
return oldValue;
}
/**
* Performs auto-injection on a setter by type of the objectToInject into the given target object or targetClass,
* depending on the value of isStatic. The object is injected to one single setter, if there is more than one
* candidate setter, a {@link UnitilsException} is thrown. We try to inject the object on the most specific type,
* this means that when there are muliple setters for one of the super-types or implemented interfaces of the setter
* type, the one that is lowest in the hierarchy is chosen (if possible, otherwise, a {@link UnitilsException} is
* thrown.
*
* @param objectToInject The object that is injected
* @param objectToInjectType The type of the object that is injected
* @param target The target object (only used when isStatic is false)
* @param targetClass The target class (only used when isStatis is true)
* @param isStatic Indicates wether injection should be performed on the target object or on the target class
* @return The object that was replaced by the injection
*/
private static Object injectIntoSetterByType(Object objectToInject, Type objectToInjectType, Object target, Class> targetClass, boolean isStatic) {
// Try to find a method with an exact matching type
Method setterToInjectTo = null;
Set settersWithExactType = getSettersOfType(targetClass, objectToInjectType, isStatic);
if (settersWithExactType.size() > 1) {
throw new UnitilsException("More than one " + (isStatic ? "static " : "") + "setter with type " + objectToInjectType + " found in " + targetClass.getSimpleName());
} else if (settersWithExactType.size() == 1) {
setterToInjectTo = settersWithExactType.iterator().next();
} else {
// Try to find a supertype setter:
// If one setter exist that has a type which is more specific than all other setters of the given type,
// this one is taken. Otherwise, an exception is thrown
Set settersOfType = getSettersAssignableFrom(targetClass, objectToInjectType, isStatic);
if (settersOfType.size() == 0) {
throw new UnitilsException("No " + (isStatic ? "static " : "") + "setter with (super)type " + objectToInjectType + " found in " + targetClass.getSimpleName());
}
for (Method setter : settersOfType) {
boolean moreSpecific = true;
for (Method compareToSetter : settersOfType) {
if (setter != compareToSetter) {
if (setter.getClass().isAssignableFrom(compareToSetter.getClass())) {
moreSpecific = false;
break;
}
}
}
if (moreSpecific) {
setterToInjectTo = setter;
break;
}
}
if (setterToInjectTo == null) {
throw new UnitilsException("Multiple candidate target " + (isStatic ? "static " : "") + "setters found in " + targetClass.getSimpleName() +
", with none of them more specific than all others.");
}
}
// Setter to inject into found, inject the object and return old value
Object oldValue = null;
try {
Method getter = getGetter(setterToInjectTo, isStatic);
if (getter == null) {
logger.warn("Unable to retrieve current value of field to inject into, no getter found for setter: " + setterToInjectTo + ". Will not be able to restore value after injection.");
} else {
oldValue = invokeMethod(target, getter);
}
} catch (Exception e) {
logger.warn("Unable to retrieve current value of field to inject into. Will not be able to restore value after injection.", e);
}
try {
invokeMethod(target, setterToInjectTo, objectToInject);
} catch (InvocationTargetException e) {
throw new UnitilsException("Unable to inject to setter, exception thrown by target.", e);
}
return oldValue;
}
/**
* Retrieves the value of the static property from the given class
*
* @param targetClass The class from which the static property value is retrieved
* @param staticProperty The name of the property (simple name, not a composite expression)
* @return The value of the static property from the given class
*/
private static Object getValueStatic(Class> targetClass, String staticProperty) {
Method staticGetter = getGetter(targetClass, staticProperty, true);
if (staticGetter != null) {
try {
return invokeMethod(targetClass, staticGetter);
} catch (InvocationTargetException e) {
throw new UnitilsException("Exception thrown by target", e);
}
} else {
Field staticField = getFieldWithName(targetClass, staticProperty, true);
if (staticField != null) {
return getFieldValue(targetClass, staticField);
} else {
throw new UnitilsException("Static property named " + staticProperty + " not found on class " + targetClass.getSimpleName());
}
}
}
/**
* Sets the given value on the static property of the given targetClass
*
* @param targetClass The class on which the static property value should be set
* @param staticProperty The name of the property (simple name, not a composite expression)
* @param value The value to set
*/
private static void setValueStatic(Class> targetClass, String staticProperty, Object value) {
Method staticSetter = ReflectionUtils.getSetter(targetClass, staticProperty, true);
if (staticSetter != null) {
try {
invokeMethod(targetClass, staticSetter, value);
} catch (InvocationTargetException e) {
throw new UnitilsException("Exception thrown by target", e);
}
} else {
Field staticField = getFieldWithName(targetClass, staticProperty, true);
if (staticField == null) {
throw new UnitilsException("Static property named " + staticProperty + " not found on class " + targetClass.getSimpleName());
}
setFieldValue(targetClass, staticField, value);
}
}
}