You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xbean-scm@geronimo.apache.org by da...@apache.org on 2008/03/20 02:36:31 UTC

svn commit: r639106 - in /geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe: ObjectRecipe.java ReflectionUtil.java

Author: dain
Date: Wed Mar 19 18:36:22 2008
New Revision: 639106

URL: http://svn.apache.org/viewvc?rev=639106&view=rev
Log:
Multiple setters and a field may be valid for a property so try each until the value can be successfully converted to setter/field type and then set

Modified:
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java?rev=639106&r1=639105&r2=639106&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java Wed Mar 19 18:36:22 2008
@@ -367,24 +367,41 @@
 
     private void setProperty(Object instance, Class clazz, Property propertyName, Object propertyValue) {
 
-        Member member;
+        List<Member> members = new ArrayList<Member>();
         try {
             if (propertyName instanceof SetterProperty){
-                member = new MethodMember(ReflectionUtil.findSetter(clazz, propertyName.name, propertyValue, options));
+                List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options);
+                for (Method setter : setters) {
+                    MethodMember member = new MethodMember(setter);
+                    members.add(member);
+                }
             } else if (propertyName instanceof FieldProperty){
-                member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options));
+                FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options));
+                members.add(member);
             } else {
+                // add setter members
+                MissingAccessorException noSetter = null;
                 try {
-                    member = new MethodMember(ReflectionUtil.findSetter(clazz, propertyName.name, propertyValue, options));
-                } catch (MissingAccessorException noSetter) {
+                    List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options);
+                    for (Method setter : setters) {
+                        MethodMember member = new MethodMember(setter);
+                        members.add(member);
+                    }
+                } catch (MissingAccessorException e) {
+                    noSetter = e;
                     if (!options.contains(Option.FIELD_INJECTION)) {
                         throw noSetter;
                     }
+                }
 
+                if (options.contains(Option.FIELD_INJECTION)) {
                     try {
-                        member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options));
+                        FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options));
+                        members.add(member);
                     } catch (MissingAccessorException noField) {
-                        throw (noField.getMatchLevel() > noSetter.getMatchLevel())? noField: noSetter;
+                        if (members.isEmpty()) {
+                            throw (noSetter == null || noField.getMatchLevel() > noSetter.getMatchLevel())? noField: noSetter;
+                        }
                     }
                 }
             }
@@ -396,19 +413,42 @@
             throw e;
         }
 
-        try {
-            propertyValue = RecipeHelper.convert(member.getType(), propertyValue, false);
-            member.setValue(instance, propertyValue);
-        } catch (Exception e) {
-            Throwable t = e;
-            if (e instanceof InvocationTargetException) {
-                InvocationTargetException invocationTargetException = (InvocationTargetException) e;
-                if (invocationTargetException.getCause() != null) {
-                    t = invocationTargetException.getCause();
+        ConstructionException conversionException = null;
+        for (Member member : members) {
+            // convert the value to type of setter/field
+            try {
+                propertyValue = RecipeHelper.convert(member.getType(), propertyValue, false);
+            } catch (Exception e) {
+                // save off first conversion exception, in case setting failed
+                if (conversionException == null) {
+                    String valueType = propertyValue == null ? "null" : propertyValue.getClass().getName();
+                    String memberType = member.getType() instanceof Class ? ((Class) member.getType()).getName() : member.getType().toString();
+                    conversionException = new ConstructionException("Unable to convert property value" +
+                            " from " + valueType +
+                            " to " + memberType +
+                            " for injection " + member, e);
                 }
+                continue;
             }
-            throw new ConstructionException("Error setting property: " + member, t);
+            try {
+                // set value
+                member.setValue(instance, propertyValue);
+            } catch (Exception e) {
+                Throwable t = e;
+                if (e instanceof InvocationTargetException) {
+                    InvocationTargetException invocationTargetException = (InvocationTargetException) e;
+                    if (invocationTargetException.getCause() != null) {
+                        t = invocationTargetException.getCause();
+                    }
+                }
+                throw new ConstructionException("Error setting property: " + member, t);
+            }
+
+            // value set successfully
+            return;
         }
+
+        throw conversionException;
     }
 
     private Factory findFactory(Type expectedType) {

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java?rev=639106&r1=639105&r2=639106&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java Wed Mar 19 18:36:22 2008
@@ -34,6 +34,8 @@
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
+import java.util.LinkedList;
+import java.util.LinkedHashSet;
 
 import static org.apache.xbean.recipe.RecipeHelper.isAssignableFrom;
 
@@ -149,6 +151,21 @@
     }
 
     public static Method findSetter(Class typeClass, String propertyName, Object propertyValue, Set<Option> options) {
+        List<Method> setters = findAllSetters(typeClass, propertyName, propertyValue, options);
+        return setters.get(0);
+    }
+
+    /**
+     * Finds all valid setters for the property.  Due to automatic type conversion there may be more than one possible
+     * setter that could be used to set the property.  The setters that do not require type converstion will be a the
+     * head of the returned list of setters.
+     * @param typeClass the class to search for setters
+     * @param propertyName the name of the property
+     * @param propertyValue the value that must be settable either directly or after conversion
+     * @param options controls which setters are considered valid
+     * @return the valid setters; never null or empty
+     */
+    public static List<Method> findAllSetters(Class typeClass, String propertyName, Object propertyValue, Set<Option> options) {
         if (typeClass == null) throw new NullPointerException("typeClass is null");
         if (propertyName == null) throw new NullPointerException("name is null");
         if (propertyName.length() == 0) throw new IllegalArgumentException("name is an empty string");
@@ -187,6 +204,9 @@
         boolean allowStatic = options.contains(Option.STATIC_PROPERTIES);
         boolean caseInsesnitive = options.contains(Option.CASE_INSENSITIVE_PROPERTIES);
 
+
+        LinkedList<Method> validSetters = new LinkedList<Method>();
+
         List<Method> methods = new ArrayList<Method>(Arrays.asList(typeClass.getMethods()));
         methods.addAll(Arrays.asList(typeClass.getDeclaredMethods()));
         for (Method method : methods) {
@@ -263,11 +283,22 @@
                     setAccessible(method);
                 }
 
-                return method;
+                if (RecipeHelper.isInstance(methodParameterType, propertyValue)) {
+                    // This setter requires no conversion, which means there can not be a conversion error.
+                    // Therefore this setter is perferred and put a the head of the list
+                    validSetters.addFirst(method);
+                } else {
+                    validSetters.add(method);
+                }
             }
 
         }
 
+        if (!validSetters.isEmpty()) {
+            // remove duplicate methods (can happen with inheritance)
+            return new ArrayList<Method>(new LinkedHashSet<Method>(validSetters));
+        }
+        
         if (missException != null) {
             throw missException;
         } else {