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 ga...@apache.org on 2009/04/30 21:46:48 UTC

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

Author: gawor
Date: Thu Apr 30 19:46:48 2009
New Revision: 770412

URL: http://svn.apache.org/viewvc?rev=770412&view=rev
Log:
basic support for compound properties

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
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.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=770412&r1=770411&r2=770412&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 Thu Apr 30 19:46:48 2009
@@ -194,6 +194,10 @@
         setProperty(new AutoMatchProperty(type), value);
     }
 
+    public void setCompoundProperty(String name, Object value) {
+        setProperty(new CompoundProperty(name), value);
+    }
+    
     private void setProperty(Property key, Object value) {
         if (value instanceof UnsetPropertiesRecipe) {
             allow(Option.IGNORE_MISSING_PROPERTIES);
@@ -424,6 +428,33 @@
                         throw new MissingAccessorException("Property of type " + propertyValue.getClass().getName() + " can be mapped to more then one setter: " + matches, 0);
                     }
                 }
+            } else if (propertyName instanceof CompoundProperty) {
+                String[] names = propertyName.name.split("\\.");
+                for (int i = 0; i < names.length - 1; i++) {
+                    Method getter = ReflectionUtil.findGetter(clazz, names[i], options);
+                    if (getter != null) {
+                        try {
+                            instance = getter.invoke(instance);
+                            clazz = instance.getClass();
+                        } 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: " + names[i], t);                            
+                        } 
+                    } else {
+                        throw new ConstructionException("No getter for " + names[i] + " property");
+                    }
+                }
+                List<Method> setters = ReflectionUtil.findAllSetters(clazz, names[names.length - 1], propertyValue, options);
+                for (Method setter : setters) {
+                    MethodMember member = new MethodMember(setter);
+                    members.add(member);
+                }
             } else {
                 // add setter members
                 MissingAccessorException noSetter = null;
@@ -703,4 +734,17 @@
             return "[auto-match] "+ super.toString();
         }
     }
+    
+    public static class CompoundProperty extends Property {
+        public CompoundProperty(String type) {
+            super(type);
+        }
+
+        public int hashCode() {
+            return super.hashCode()+1;
+        }
+        public String toString() {
+            return "[compound] "+ super.toString();
+        }
+    }
 }

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=770412&r1=770411&r2=770412&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 Thu Apr 30 19:46:48 2009
@@ -150,6 +150,72 @@
         }
     }
 
+    public static Method findGetter(Class typeClass, String propertyName, 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");
+        if (options == null) options = EnumSet.noneOf(Option.class);
+
+        if (propertyName.contains("/")){
+            String[] strings = propertyName.split("/");
+            if (strings == null || strings.length != 2) throw new IllegalArgumentException("badly formed <class>/<attribute> property name: " + propertyName);
+
+            String className = strings[0];
+            propertyName = strings[1];
+
+            boolean found = false;
+            while(!typeClass.equals(Object.class) && !found){
+                if (typeClass.getName().equals(className)){
+                    found = true;
+                    break;
+                } else {
+                    typeClass = typeClass.getSuperclass();
+                }
+            }
+
+            if (!found) throw new MissingAccessorException("Type not assignable to class: " + className, -1);
+        }
+
+        String getterName = "get" + Character.toUpperCase(propertyName.charAt(0));
+        if (propertyName.length() > 0) {
+            getterName += propertyName.substring(1);
+        }
+        
+        boolean allowPrivate = options.contains(Option.PRIVATE_PROPERTIES);
+        boolean allowStatic = options.contains(Option.STATIC_PROPERTIES);
+        boolean caseInsesnitive = options.contains(Option.CASE_INSENSITIVE_PROPERTIES);
+
+        List<Method> methods = new ArrayList<Method>(Arrays.asList(typeClass.getMethods()));
+        methods.addAll(Arrays.asList(typeClass.getDeclaredMethods()));
+        for (Method method : methods) {
+            if (method.getName().equals(getterName) || (caseInsesnitive && method.getName().equalsIgnoreCase(getterName))) {
+                if (method.getParameterTypes().length > 0) {
+                    continue;
+                }
+                if (method.getReturnType() == Void.TYPE) {
+                    continue;
+                }
+                if (Modifier.isAbstract(method.getModifiers())) {
+                    continue;
+                }
+                if (!allowPrivate && !Modifier.isPublic(method.getModifiers())) {
+                    continue;
+                }
+                if (!allowStatic && Modifier.isStatic(method.getModifiers())) {
+                    continue;
+                }
+
+                if (allowPrivate && !Modifier.isPublic(method.getModifiers())) {
+                    setAccessible(method);
+                }
+                
+                return method;
+            }
+        }
+        
+        return null;
+    }
+    
     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);

Modified: geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java?rev=770412&r1=770411&r2=770412&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java Thu Apr 30 19:46:48 2009
@@ -127,4 +127,58 @@
         assertEquals(expectedConstruction, actual.getConstructionCalled());
     }
 
+    public void testCompoundProperties() throws Exception {
+        ObjectRecipe objectRecipe = new ObjectRecipe(Component.class);
+        objectRecipe.setCompoundProperty("name", "Adam");
+        objectRecipe.setCompoundProperty("box.height", 5);
+        objectRecipe.setCompoundProperty("box.width", 10);
+        
+        objectRecipe.setCompoundProperty("component.name", "Eva");
+        objectRecipe.setCompoundProperty("component.box.height", 10);
+        objectRecipe.setCompoundProperty("component.box.width", 20);
+                
+        Component component = (Component) objectRecipe.create(Component.class.getClassLoader());
+        
+        assertEquals("Adam", component.getName());
+        assertEquals(5, component.getBox().getHeight());
+        assertEquals(10, component.getBox().getWidth());
+        
+        assertEquals("Eva", component.getComponent().getName());
+        assertEquals(10, component.getComponent().getBox().getHeight());
+        assertEquals(20, component.getComponent().getBox().getWidth());
+    }
+    
+    public static class Component {
+                
+        String name;
+        Box box;
+        Component component;
+        
+        public Box getBox() {
+            if (box == null) {
+                box = new Box();
+            }
+            return box;
+        }
+        
+        public Component getComponent() {
+            if (component == null) {
+                component = new Component();
+            }
+            return component;
+        }
+        
+        public Component getNullComponent() {
+            return null;
+        }
+        
+        public void setName(String name) {
+            this.name = name;
+        }
+        
+        public String getName() {
+            return name;
+        }                
+            
+    }
 }