You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ma...@apache.org on 2010/02/16 10:50:19 UTC
svn commit: r910448 - in /incubator/aries/trunk/blueprint/blueprint-core/src:
main/java/org/apache/aries/blueprint/
main/java/org/apache/aries/blueprint/container/
main/java/org/apache/aries/blueprint/ext/
main/java/org/apache/aries/blueprint/mutable/ ...
Author: mahrwald
Date: Tue Feb 16 09:50:18 2010
New Revision: 910448
URL: http://svn.apache.org/viewvc?rev=910448&view=rev
Log:
ARIES-88 Initial drop for field injection
Added:
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestBean.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestSubBean.java
Modified:
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/mutable/MutableBeanMetadata.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/resources/org/apache/aries/blueprint/ext/blueprint-ext.xsd
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/WiringTest.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/resources/test-wiring.xml
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java Tue Feb 16 09:50:18 2010
@@ -41,4 +41,10 @@
Class<?> getRuntimeClass();
+ /**
+ * Whether the bean allows properties to be injected directly into its fields in the case
+ * where an appropriate setter method is not available.
+ * @return Whether field injection is allowed
+ */
+ boolean getFieldInjection();
}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java Tue Feb 16 09:50:18 2010
@@ -41,6 +41,7 @@
import org.apache.aries.blueprint.proxy.AsmInterceptorWrapper;
import org.apache.aries.blueprint.proxy.CgLibInterceptorWrapper;
import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.apache.aries.blueprint.utils.ReflectionUtils.PropertyDescriptor;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
import org.osgi.service.blueprint.container.ReifiedType;
import org.osgi.service.blueprint.reflect.BeanMetadata;
@@ -70,12 +71,14 @@
private List<Object> arguments;
private List<String> argTypes;
private boolean reorderArguments;
+ private final boolean allowsFieldInjection;
- public BeanRecipe(String name, ExtendedBlueprintContainer blueprintContainer, Object type) {
+ public BeanRecipe(String name, ExtendedBlueprintContainer blueprintContainer, Object type, boolean allowsFieldInjection) {
super(name);
this.blueprintContainer = blueprintContainer;
this.type = type;
+ this.allowsFieldInjection = allowsFieldInjection;
}
public Object getProperty(String name) {
@@ -744,10 +747,10 @@
private void setProperty(Object instance, Class clazz, String propertyName, Object propertyValue) {
String[] names = propertyName.split("\\.");
for (int i = 0; i < names.length - 1; i++) {
- Method getter = getPropertyDescriptor(clazz, names[i]).getGetter();
- if (getter != null) {
+ PropertyDescriptor pd = getPropertyDescriptor(clazz, names[i]);
+ if (pd.allowsGet()) {
try {
- instance = invoke(getter, instance, (Object[]) null);
+ instance = pd.get(instance, blueprintContainer.getAccessControlContext());
} catch (Exception e) {
throw new ComponentDefinitionException("Error getting property: " + names[i] + " on bean " + getName() + " when setting property " + propertyName + " on class " + clazz.getName(), getRealCause(e));
}
@@ -759,10 +762,10 @@
throw new ComponentDefinitionException("No getter for " + names[i] + " property on bean " + getName() + " when setting property " + propertyName + " on class " + clazz.getName());
}
}
- Method setter = getPropertyDescriptor(clazz, names[names.length - 1]).getSetter();
- if (setter != null) {
+ final PropertyDescriptor pd = getPropertyDescriptor(clazz, names[names.length - 1]);
+ if (pd.allowsSet()) {
// convert the value to type of setter/field
- Type type = setter.getGenericParameterTypes()[0];
+ Type type = pd.getGenericType();
// Instanciate value
if (propertyValue instanceof Recipe) {
propertyValue = ((Recipe) propertyValue).create();
@@ -775,21 +778,20 @@
throw new ComponentDefinitionException("Unable to convert property value" +
" from " + valueType +
" to " + memberType +
- " for injection " + setter, e);
+ " for injection " + pd, e);
}
try {
- // set value
- invoke(setter, instance, propertyValue);
+ pd.set(instance, propertyValue, blueprintContainer.getAccessControlContext());
} catch (Exception e) {
- throw new ComponentDefinitionException("Error setting property: " + setter, getRealCause(e));
+ throw new ComponentDefinitionException("Error setting property: " + pd, getRealCause(e));
}
} else {
throw new ComponentDefinitionException("No setter for " + names[names.length - 1] + " property");
}
}
- private ReflectionUtils.PropertyDescriptor getPropertyDescriptor(Class clazz, String name) {
- for (ReflectionUtils.PropertyDescriptor pd : ReflectionUtils.getPropertyDescriptors(clazz)) {
+ private ReflectionUtils.PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String name) {
+ for (ReflectionUtils.PropertyDescriptor pd : ReflectionUtils.getPropertyDescriptors(clazz, allowsFieldInjection)) {
if (pd.getName().equals(name)) {
return pd;
}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java Tue Feb 16 09:50:18 2010
@@ -210,11 +210,19 @@
return beanMetadata.getClassName();
}
+ private boolean allowsFieldInjection(BeanMetadata beanMetadata) {
+ if (beanMetadata instanceof ExtendedBeanMetadata) {
+ return ((ExtendedBeanMetadata) beanMetadata).getFieldInjection();
+ }
+ return false;
+ }
+
private BeanRecipe createBeanRecipe(BeanMetadata beanMetadata) {
BeanRecipe recipe = new BeanRecipe(
getName(beanMetadata.getId()),
blueprintContainer,
- getBeanClass(beanMetadata));
+ getBeanClass(beanMetadata),
+ allowsFieldInjection(beanMetadata));
// Create refs for explicit dependencies
recipe.setExplicitDependencies(getDependencies(beanMetadata));
recipe.setPrototype(MetadataUtil.isPrototypeScope(beanMetadata));
@@ -251,7 +259,7 @@
}
private Recipe createRecipe(RegistrationListener listener) {
- BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, ServiceListener.class);
+ BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, ServiceListener.class, false);
recipe.setProperty("listener", getValue(listener.getListenerComponent(), null));
if (listener.getRegistrationMethod() != null) {
recipe.setProperty("registerMethod", listener.getRegistrationMethod());
@@ -264,7 +272,7 @@
}
private Recipe createRecipe(ReferenceListener listener) {
- BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, AbstractServiceReferenceRecipe.Listener.class);
+ BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, AbstractServiceReferenceRecipe.Listener.class, false);
recipe.setProperty("listener", getValue(listener.getListenerComponent(), null));
recipe.setProperty("metadata", listener);
recipe.setProperty("blueprintContainer", blueprintContainer);
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java Tue Feb 16 09:50:18 2010
@@ -25,14 +25,6 @@
import java.util.List;
import java.util.Set;
-import org.w3c.dom.Attr;
-import org.w3c.dom.CharacterData;
-import org.w3c.dom.Comment;
-import org.w3c.dom.Element;
-import org.w3c.dom.EntityReference;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
import org.apache.aries.blueprint.ExtendedReferenceListMetadata;
import org.apache.aries.blueprint.ParserContext;
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
@@ -50,12 +42,19 @@
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.osgi.service.blueprint.reflect.IdRefMetadata;
import org.osgi.service.blueprint.reflect.Metadata;
-import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
import org.osgi.service.blueprint.reflect.RefMetadata;
+import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
import org.osgi.service.blueprint.reflect.ValueMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* A namespace handler for Aries blueprint extensions
@@ -91,6 +90,8 @@
public static final String ROLE_ATTRIBUTE = "role";
public static final String ROLE_PROCESSOR = "processor";
+
+ public static final String FIELD_INJECTION_ATTRIBUTE = "field-injection";
private static final Logger LOGGER = LoggerFactory.getLogger(ExtNamespaceHandler.class);
@@ -120,10 +121,26 @@
return decorateProxyMethod(node, component, context);
} else if (node instanceof Attr && nodeNameEquals(node, ROLE_ATTRIBUTE)) {
return decorateRole(node, component, context);
+ } else if (node instanceof Attr && nodeNameEquals(node, FIELD_INJECTION_ATTRIBUTE)) {
+ return decorateFieldInjection(node, component, context);
} else {
throw new ComponentDefinitionException("Unsupported node: " + node.getNodeName());
}
}
+
+ private ComponentMetadata decorateFieldInjection(Node node, ComponentMetadata component, ParserContext context) {
+ if (!(component instanceof BeanMetadata)) {
+ throw new ComponentDefinitionException("Attribute " + node.getNodeName() + " can only be used on a <bean> element");
+ }
+
+ if (!(component instanceof MutableBeanMetadata)) {
+ throw new ComponentDefinitionException("Expected an instanceof MutableBeanMetadata");
+ }
+
+ String value = ((Attr) node).getValue();
+ ((MutableBeanMetadata) component).setFieldInjection("true".equals(value) || "1".equals(value));
+ return component;
+ }
private ComponentMetadata decorateRole(Node node, ComponentMetadata component, ParserContext context) {
if (!(component instanceof BeanMetadata)) {
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/mutable/MutableBeanMetadata.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/mutable/MutableBeanMetadata.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/mutable/MutableBeanMetadata.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/mutable/MutableBeanMetadata.java Tue Feb 16 09:50:18 2010
@@ -58,5 +58,7 @@
void setRuntimeClass(Class runtimeClass);
void setProcessor(boolean processor);
+
+ void setFieldInjection(boolean allowFieldInjection);
}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/reflect/BeanMetadataImpl.java Tue Feb 16 09:50:18 2010
@@ -48,8 +48,10 @@
private String scope;
private Class runtimeClass;
private boolean processor;
-
+ private boolean fieldInjection;
+
public BeanMetadataImpl() {
+ this.fieldInjection = false;
}
public BeanMetadataImpl(BeanMetadata source) {
@@ -70,6 +72,9 @@
this.dependsOn = new ArrayList<String>(source.getDependsOn());
if (source instanceof ExtendedBeanMetadata) {
this.runtimeClass = ((ExtendedBeanMetadata) source).getRuntimeClass();
+ this.fieldInjection = ((ExtendedBeanMetadata) source).getFieldInjection();
+ } else {
+ this.fieldInjection = false;
}
}
@@ -199,6 +204,14 @@
this.processor = processor;
}
+ public boolean getFieldInjection() {
+ return fieldInjection;
+ }
+
+ public void setFieldInjection(boolean fieldInjection) {
+ this.fieldInjection = fieldInjection;
+ }
+
@Override
public String toString() {
return "BeanMetadata[" +
@@ -214,6 +227,7 @@
", factoryComponent=" + factoryComponent +
", scope='" + scope + '\'' +
", runtimeClass=" + runtimeClass +
+ ", fieldInjection=" + fieldInjection +
']';
}
}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java Tue Feb 16 09:50:18 2010
@@ -19,15 +19,20 @@
package org.apache.aries.blueprint.utils;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -41,7 +46,7 @@
public class ReflectionUtils {
// TODO: MLK: PropertyDescriptor holds a reference to Method which holds a reference to the Class itself
- private static Map<Class, PropertyDescriptor[]> beanInfos = Collections.synchronizedMap(new WeakHashMap<Class, PropertyDescriptor[]>());
+ private static Map<Class<?>, PropertyDescriptor[][]> beanInfos = Collections.synchronizedMap(new WeakHashMap<Class<?>, PropertyDescriptor[][]>());
public static boolean hasDefaultConstructor(Class type) {
if (!Modifier.isPublic(type.getModifiers())) {
@@ -114,74 +119,97 @@
return methods;
}
- public static PropertyDescriptor[] getPropertyDescriptors(Class clazz) {
- PropertyDescriptor[] properties = beanInfos.get(clazz);
+ public static PropertyDescriptor[] getPropertyDescriptors(Class clazz, boolean allowFieldInjection) {
+ PropertyDescriptor[][] properties = beanInfos.get(clazz);
+ int index = allowFieldInjection ? 0 : 1;
+
if (properties == null) {
- List<PropertyDescriptor> props = new ArrayList<PropertyDescriptor>();
+ properties = new PropertyDescriptor[2][];
+ beanInfos.put(clazz, properties);
+ }
+
+ if (properties[index] == null) {
+ Map<String,PropertyDescriptor> props = new HashMap<String, PropertyDescriptor>();
for (Method method : clazz.getMethods()) {
if (Modifier.isStatic(method.getModifiers()) || method.isBridge()) {
continue;
}
String name = method.getName();
- Class argTypes[] = method.getParameterTypes();
- Class resultType = method.getReturnType();
+ Class<?> argTypes[] = method.getParameterTypes();
+ Class<?> resultType = method.getReturnType();
+
+ Class<?> argType = resultType;
+ Method getter = null;
+ Method setter = null;
+
if (name.length() > 3 && name.startsWith("set") && resultType == Void.TYPE && argTypes.length == 1) {
- props.add(new PropertyDescriptor(decapitalize(name.substring(3)), argTypes[0], null, method));
-
+ name = decapitalize(name.substring(3));
+ setter = method;
+ argType = argTypes[0];
} else if (name.length() > 3 && name.startsWith("get") && argTypes.length == 0) {
- props.add(new PropertyDescriptor(decapitalize(name.substring(3)), resultType, method, null));
+ name = decapitalize(name.substring(3));
+ getter = method;
} else if (name.length() > 2 && name.startsWith("is") && argTypes.length == 0 && resultType == boolean.class) {
- props.add(new PropertyDescriptor(decapitalize(name.substring(2)), resultType, method, null));
+ name = decapitalize(name.substring(2));
+ getter = method;
+ } else {
+ continue;
}
- }
- PropertyDescriptor[] pds = props.toArray(new PropertyDescriptor[props.size()]);
- for (int i = 0; i < pds.length - 1; i++) {
- boolean remove = false;
- for (int j = i + 1; j < pds.length; j++) {
- if (pds[i] != null && pds[j] != null) {
- if (pds[i].name.equals(pds[j].name)) {
- if (remove || !pds[i].type.equals(pds[j].type)) {
- remove = true;
- pds[j] = null;
- continue;
- } else {
- if (pds[j].getter != null) {
- if (pds[i].getter == null) {
- pds[i].getter = pds[j].getter;
- } else if (pds[i].getter != pds[j].getter) {
- remove = true;
- pds[j] = null;
- continue;
- }
- }
- if (pds[j].setter != null) {
- if (pds[i].setter == null) {
- pds[i].setter = pds[j].setter;
- } else if (pds[i].setter != pds[j].setter) {
- remove = true;
- pds[j] = null;
- continue;
- }
- }
- }
+
+ if (props.containsKey(name)) {
+ PropertyDescriptor pd = props.get(name);
+ if (pd != INVALID_PROPERTY) {
+ if (!argType.equals(pd.type)) {
+ props.put(name, INVALID_PROPERTY);
+ } else if (getter != null) {
+ if (pd.getter == null || pd.getter.equals(getter))
+ pd.getter = getter;
+ else
+ props.put(name, INVALID_PROPERTY);
+ } else if (setter != null) {
+ if (pd.setter == null || pd.setter.equals(setter))
+ pd.setter = setter;
+ else
+ props.put(name, INVALID_PROPERTY);
}
}
- }
- if (remove) {
- pds[i] = null;
+ } else {
+ props.put(name, new PropertyDescriptor(name, argType, getter, setter));
}
}
- props.clear();
- for (int i = 0; i < pds.length - 1; i++) {
- if (pds[i] != null) {
- pds[i].type = null;
- props.add(pds[i]);
+
+ if (allowFieldInjection) {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+
+ String name = decapitalize(field.getName());
+ if (!props.containsKey(name)) {
+ props.put(name, new PropertyDescriptor(name, field.getType(), field));
+ } else {
+ PropertyDescriptor pd = props.get(name);
+ if (pd != INVALID_PROPERTY) {
+ if (pd.type.equals(field.getType())) {
+ pd.field = field;
+ }
+ // no else, we don't require field implementations to have the same
+ // type as the getter and setter
+ }
+ }
}
}
- properties = props.toArray(new PropertyDescriptor[props.size()]);
- beanInfos.put(clazz, properties);
+
+ Iterator<PropertyDescriptor> it = props.values().iterator();
+ while (it.hasNext()) {
+ if (it.next() == INVALID_PROPERTY)
+ it.remove();
+ }
+
+ Collection<PropertyDescriptor> tmp = props.values();
+ properties[index] = tmp.toArray(new PropertyDescriptor[tmp.size()]);
}
- return properties;
+ return properties[index];
}
private static String decapitalize(String name) {
@@ -245,29 +273,112 @@
}
}
+ private static final PropertyDescriptor INVALID_PROPERTY = new PropertyDescriptor(null, null, null, null);
+
public static class PropertyDescriptor {
private String name;
- private Class type;
+ private Class<?> type;
private Method getter;
private Method setter;
+ private Field field;
- public PropertyDescriptor(String name, Class type, Method getter, Method setter) {
+ public PropertyDescriptor(String name, Class<?> type, Method getter, Method setter) {
this.name = name;
this.type = type;
this.getter = getter;
this.setter = setter;
}
+
+ public PropertyDescriptor(String name, Class<?> type, Field field) {
+ this.name = name;
+ this.type = type;
+ this.field = field;
+ this.getter = null;
+ this.setter = null;
+ }
public String getName() {
return name;
}
-
- public Method getGetter() {
- return getter;
+
+ public boolean allowsGet() {
+ return getter != null || field != null;
+ }
+
+ public boolean allowsSet() {
+ return setter != null || field != null;
+ }
+
+ public Object get(final Object instance, AccessControlContext acc) throws Exception {
+ if (acc == null) {
+ return internalGet(instance);
+ } else {
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ return internalGet(instance);
+ }
+ }, acc);
+ } catch (PrivilegedActionException e) {
+ throw e.getException();
+ }
+ }
+ }
+
+ private Object internalGet(Object instance)
+ throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ if (getter != null) {
+ return getter.invoke(instance);
+ } else if (field != null) {
+ field.setAccessible(true);
+ return field.get(instance);
+ } else {
+ throw new UnsupportedOperationException();
+ }
}
- public Method getSetter() {
- return setter;
+ public void set(final Object instance, final Object value, AccessControlContext acc) throws Exception {
+ if (acc == null) {
+ internalSet(instance, value);
+ } else {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ internalSet(instance, value);
+ return null;
+ }
+ }, acc);
+ } catch (PrivilegedActionException e) {
+ throw e.getException();
+ }
+ }
+ }
+
+ private void internalSet(Object instance, Object value)
+ throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ if (setter != null) {
+ setter.invoke(instance, value);
+ } else if (field != null) {
+ field.setAccessible(true);
+ field.set(instance, value);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public Type getGenericType() {
+ if (setter != null)
+ return setter.getGenericParameterTypes()[0];
+ else if (getter != null)
+ return getter.getGenericReturnType();
+ else
+ return field.getGenericType();
+
+ }
+
+ public String toString() {
+ return "PropertyDescriptor <name: "+name+", getter: "+getter+", setter: "+setter+
+ ", field: "+field+">";
}
}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/resources/org/apache/aries/blueprint/ext/blueprint-ext.xsd
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/resources/org/apache/aries/blueprint/ext/blueprint-ext.xsd?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/resources/org/apache/aries/blueprint/ext/blueprint-ext.xsd (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/resources/org/apache/aries/blueprint/ext/blueprint-ext.xsd Tue Feb 16 09:50:18 2010
@@ -114,5 +114,7 @@
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
+
+ <xsd:attribute name="field-injection" type="xsd:boolean" default="false" />
</xsd:schema>
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java Tue Feb 16 09:50:18 2010
@@ -29,18 +29,24 @@
import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
import org.apache.aries.blueprint.container.Parser;
+import org.apache.aries.blueprint.ext.ExtNamespaceHandler;
import org.apache.aries.blueprint.namespace.ComponentDefinitionRegistryImpl;
import org.xml.sax.SAXException;
public abstract class AbstractBlueprintTest extends TestCase {
protected ComponentDefinitionRegistryImpl parse(String name) throws Exception {
- NamespaceHandlerRegistry.NamespaceHandlerSet handlers = new NamespaceHandlerRegistry.NamespaceHandlerSet() {
+ final URI extensionHandler = new URI("http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0");
+ NamespaceHandlerRegistry.NamespaceHandlerSet handlers = new NamespaceHandlerRegistry.NamespaceHandlerSet() {
public Set<URI> getNamespaces() {
return null;
}
public NamespaceHandler getNamespaceHandler(URI namespace) {
- return null;
+ if (namespace.equals(extensionHandler)) {
+ return new ExtNamespaceHandler();
+ } else {
+ return null;
+ }
}
public void removeListener(NamespaceHandlerRegistry.Listener listener) {
}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/WiringTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/WiringTest.java?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/WiringTest.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/WiringTest.java Tue Feb 16 09:50:18 2010
@@ -28,6 +28,8 @@
import java.util.Map;
import java.util.Set;
+import junit.framework.Assert;
+
import org.apache.aries.blueprint.CallbackTracker.Callback;
import org.apache.aries.blueprint.container.BlueprintRepository;
import org.apache.aries.blueprint.di.CircularDependencyException;
@@ -35,6 +37,7 @@
import org.apache.aries.blueprint.namespace.ComponentDefinitionRegistryImpl;
import org.apache.aries.blueprint.pojos.BeanD;
import org.apache.aries.blueprint.pojos.BeanF;
+import org.apache.aries.blueprint.pojos.FITestBean;
import org.apache.aries.blueprint.pojos.Multiple;
import org.apache.aries.blueprint.pojos.PojoA;
import org.apache.aries.blueprint.pojos.PojoB;
@@ -135,6 +138,35 @@
assertEquals(true, pojob.getDestroyCalled());
}
+ public void testFieldInjection() throws Exception {
+ ComponentDefinitionRegistryImpl registry = parse("/test-wiring.xml");
+ Repository repository = new TestBlueprintContainer(registry).getRepository();
+
+ Object fiTestBean = repository.create("FITestBean");
+ assertNotNull(fiTestBean);
+ assertTrue(fiTestBean instanceof FITestBean);
+
+ FITestBean bean = (FITestBean) fiTestBean;
+ // single field injection
+ assertEquals("value", bean.getAttr());
+ // prefer setter injection to field injection
+ assertEquals("IS_LOWER", bean.getUpperCaseAttr());
+ // support cascaded injection 'bean.name' via fields
+ assertEquals("aName", bean.getBeanName());
+
+ // fail if field-injection is not specified
+ try {
+ repository.create("FIFailureTestBean");
+ Assert.fail("Expected exception");
+ } catch (ComponentDefinitionException cde) {}
+
+ // fail if field-injection is false
+ try {
+ repository.create("FIFailureTest2Bean");
+ Assert.fail("Expected exception");
+ } catch (ComponentDefinitionException cde) {}
+ }
+
public void testCompoundProperties() throws Exception {
ComponentDefinitionRegistryImpl registry = parse("/test-wiring.xml");
Repository repository = new TestBlueprintContainer(registry).getRepository();
Added: incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestBean.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestBean.java?rev=910448&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestBean.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestBean.java Tue Feb 16 09:50:18 2010
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.aries.blueprint.pojos;
+
+public class FITestBean {
+ private String attr;
+ private String upperCaseAttr;
+ private FITestSubBean bean = new FITestSubBean();
+
+ public String getAttr() { return attr; }
+
+ public String getUpperCaseAttr() { return upperCaseAttr; }
+ public void setUpperCaseAttr(String val) { upperCaseAttr = val.toUpperCase(); }
+ public String getBeanName() { return bean.getName(); }
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestSubBean.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestSubBean.java?rev=910448&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestSubBean.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/FITestSubBean.java Tue Feb 16 09:50:18 2010
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.aries.blueprint.pojos;
+
+public class FITestSubBean {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/test/resources/test-wiring.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/resources/test-wiring.xml?rev=910448&r1=910447&r2=910448&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/resources/test-wiring.xml (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/resources/test-wiring.xml Tue Feb 16 09:50:18 2010
@@ -16,6 +16,7 @@
limitations under the License.
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
default-availability="mandatory" >
<type-converters>
@@ -116,5 +117,19 @@
<idref component-id="pojoA"/>
</property>
</bean>
+
+ <bean id="FITestBean" ext:field-injection="true" class="org.apache.aries.blueprint.pojos.FITestBean">
+ <property name="attr" value="value" />
+ <property name="upperCaseAttr" value="is_lower" />
+ <property name="bean.name" value="aName" />
+ </bean>
+
+ <bean id="FIFailureTestBean" class="org.apache.aries.blueprint.pojos.FITestBean">
+ <property name="attr" value="value" />
+ </bean>
+
+ <bean id="FIFailureTest2Bean" class="org.apache.aries.blueprint.pojos.FITestBean" ext:field-injection="false">
+ <property name="attr" value="value" />
+ </bean>
</blueprint>
\ No newline at end of file