You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by da...@apache.org on 2006/05/16 22:08:45 UTC

svn commit: r407045 - in /geronimo/xbean/branches/xbean-reflect-args/src: main/java/org/apache/xbean/ main/java/org/apache/xbean/recipe/ main/java/org/apache/xbean/util/ test/java/org/apache/xbean/recipe/ test/java/org/apache/xbean/util/

Author: dain
Date: Tue May 16 13:08:43 2006
New Revision: 407045

URL: http://svn.apache.org/viewcvs?rev=407045&view=rev
Log:
Added automatic constructor arg name detection

Added:
    geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/CloseMatchException.java
    geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/AsmParameterNames.java
Modified:
    geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/ClassLoading.java
    geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
    geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/ParameterNames.java
    geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java
    geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/Person.java
    geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/util/ParameterNamesTest.java

Modified: geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/ClassLoading.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/ClassLoading.java?rev=407045&r1=407044&r2=407045&view=diff
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/ClassLoading.java (original)
+++ geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/ClassLoading.java Tue May 16 13:08:43 2006
@@ -116,6 +116,12 @@
         if (classLoader == null) {
             throw new IllegalArgumentException("classLoader is null");
         }
+
+        // in some cases we get class names contianing slashes '/' instead of dots '.'
+        // we can just blindly replace all slahses with dots since a class name or
+        // package names can't contain a slash
+        className = className.replace('/', '.');
+
         // The easiest case is a proper class name.  We just have the class loader resolve this.
         // If the class loader throws a ClassNotFoundException, then we need to check each of the
         // special name encodings we support.

Added: geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/CloseMatchException.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/CloseMatchException.java?rev=407045&view=auto
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/CloseMatchException.java (added)
+++ geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/CloseMatchException.java Tue May 16 13:08:43 2006
@@ -0,0 +1,194 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation
+ *
+ *  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.apache.xbean.recipe;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.ListIterator;
+
+import org.apache.xbean.ClassLoading;
+
+/**
+ * @version $Rev$ $Date$
+ */
+class CloseMatchException extends ConstructionException {
+    private final int level;
+    private final Method method;
+    private final Constructor constructor;
+
+    public static CloseMatchException greater(CloseMatchException m1, CloseMatchException m2) {
+        if (m1 == null) return m2;
+        if (m2 == null) return m1;
+
+        if (m1.level < m2.level) {
+            return m2;
+        } else {
+            return m1;
+        }
+    }
+
+    public static CloseMatchException setterNoParameters(Method method) {
+        return new CloseMatchException(1,
+                "Setter takes no parameters",
+                method);
+    }
+
+    public static CloseMatchException setterMultipleParameters(Method method) {
+        return new CloseMatchException(1,
+                "Setter takes more then one parameter",
+                method);
+    }
+
+    public static CloseMatchException setterWithReturn(Method method) {
+        return new CloseMatchException(2,
+                "Setter returns a value",
+                method);
+    }
+
+    public static CloseMatchException setterIsAbstract(Method method) {
+        return new CloseMatchException(3,
+                "Setter is abstract",
+                method);
+    }
+
+    public static CloseMatchException setterIsNotPublic(Method method) {
+        return new CloseMatchException(4,
+                "Setter is not publict",
+                method);
+    }
+
+    public static CloseMatchException setterIsStatic(Method method) {
+        return new CloseMatchException(4,
+                "Setter is static",
+                method);
+    }
+
+    public static CloseMatchException typeMismatch(Method method, Object propertyValue) {
+        Class methodParameterType = method.getParameterTypes()[0];
+        return new CloseMatchException(5,
+                ClassLoading.getClassName(propertyValue, true) + " can not be assigned or converted to " +
+                    ClassLoading.getClassName(methodParameterType, true),
+                method);
+    }
+
+    public static CloseMatchException assignNullToPrimitive(Method method) {
+        Class methodParameterType = method.getParameterTypes()[0];
+        return new CloseMatchException(6,
+                "Null can not be assigned to primitive type " + ClassLoading.getClassName(methodParameterType, true),
+                method);
+    }
+
+    public static CloseMatchException factoryMethodIsNotPublic(Method method) {
+        return new CloseMatchException(20,
+                "Factory method is not public",
+                method);
+    }
+
+    public static CloseMatchException factoryMethodIsNotStatic(Method method) {
+        return new CloseMatchException(20,
+                "Factory method is not static",
+                method);
+    }
+
+    public static CloseMatchException factoryMethodWithNoReturn(Method method) {
+        return new CloseMatchException(20,
+                "Factory method does not return anything",
+                method);
+    }
+
+    public static CloseMatchException factoryMethodReturnsPrimitive(Method method) {
+        return new CloseMatchException(20,
+                "Factory method returns a primitive type",
+                method);
+    }
+
+    public static CloseMatchException typeMismatch(Constructor consturctor, String[] parameterNames, Class[] propertyTypes) {
+        Class[] parameterTypes = consturctor.getParameterTypes();
+        String message = createTypeMismatchMessage(parameterTypes, propertyTypes, parameterNames);
+
+        return new CloseMatchException(10,
+                message.toString(),
+                consturctor);
+    }
+
+    public static CloseMatchException typeMismatch(Method method, String[] parameterNames, Class[] propertyTypes) {
+        Class[] parameterTypes = method.getParameterTypes();
+        String message = createTypeMismatchMessage(parameterTypes, propertyTypes, parameterNames);
+
+        return new CloseMatchException(10,
+                message.toString(),
+                method);
+    }
+
+    private static String createTypeMismatchMessage(Class[] expectedTypes, Class[] actualTypes, String[] parameterNames) {
+        List badParameters = new ArrayList();
+        for (int i = 0; i < expectedTypes.length; i++) {
+            Class parameterType = expectedTypes[i];
+            if (!ObjectRecipe.isAssignableFrom(parameterType,  actualTypes[i])) {
+                badParameters.add(parameterNames[i] + " (" + i + ") to " + ClassLoading.getClassName(parameterType, true));
+            }
+        }
+
+        StringBuffer message = new StringBuffer();
+        if (badParameters.size() == 1) {
+            message.append("Unable to covert parameter ");
+            message.append(badParameters.get(0));
+        } else {
+            message.append("Unable to covert parameters ");
+            for (ListIterator iterator = badParameters.listIterator(); iterator.hasNext();) {
+                String s = (String) iterator.next();
+                int index = iterator.previousIndex();
+                if (index == badParameters.size() - 1) {
+                    message.append(" and ");
+                }
+                if (index > 0) {
+                    message.append(", ");
+                }
+                message.append(s);
+            }
+        }
+        return message.toString();
+    }
+
+    public CloseMatchException(int level, String message, Method method) {
+        super(message);
+        this.level = level;
+        this.method = method;
+        this.constructor = null;
+    }
+
+    public CloseMatchException(int level, String message, Constructor constructor) {
+        super(message);
+        this.level = level;
+        this.method = null;
+        this.constructor = constructor;
+    }
+
+    public int getLevel() {
+        return level;
+    }
+
+    public Method getMethod() {
+        return method;
+    }
+
+    public Constructor getConstructor() {
+        return constructor;
+    }
+}

Modified: geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java?rev=407045&r1=407044&r2=407045&view=diff
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java (original)
+++ geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java Tue May 16 13:08:43 2006
@@ -16,36 +16,37 @@
  */
 package org.apache.xbean.recipe;
 
-import org.apache.xbean.ClassLoading;
-import org.apache.xbean.util.ParameterNames;
-import org.apache.xbean.propertyeditor.PropertyEditors;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Comparator;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import org.apache.xbean.ClassLoading;
+import org.apache.xbean.propertyeditor.PropertyEditors;
+import org.apache.xbean.util.ParameterNames;
+import org.apache.xbean.util.AsmParameterNames;
+
 /**
  * @version $Rev: 6688 $ $Date: 2005-12-29T02:08:29.200064Z $
  */
 public class ObjectRecipe implements Recipe {
-    // todo add instanceMethod
-    // todo life cycle methods
+    private static final ParameterNames parameterNames = new AsmParameterNames();
+    // todo add instanceFactoryMethod
     private final String type;
     private final String factoryMethod;
     private final LinkedHashMap properties;
+    private String postConstruct;
+    private String preDestroy;
 
     public ObjectRecipe(Class type) {
         this(type.getName());
@@ -59,35 +60,19 @@
         this(type.getName(), properties);
     }
 
-    public ObjectRecipe(Class type, String[] constructorArgNames, Class[] constructorArgTypes) {
-        this(type.getName(), constructorArgNames, constructorArgTypes);
-    }
-
-    public ObjectRecipe(Class type, String factoryMethod, String[] constructorArgNames, Class[] constructorArgTypes) {
-        this(type.getName(), factoryMethod, constructorArgNames, constructorArgTypes);
+    public ObjectRecipe(String typeName, Map properties) {
+        this(typeName, null, properties);
     }
 
     public ObjectRecipe(String typeName) {
-        this(typeName, null, null, null, null);
+        this(typeName, null, null);
     }
 
     public ObjectRecipe(String typeName, String factoryMethod) {
-        this(typeName, factoryMethod, null, null, null);
-    }
-
-    public ObjectRecipe(String typeName, Map properties) {
-        this(typeName, null, null, null, properties);
-    }
-
-    public ObjectRecipe(String typeName, String[] constructorArgNames, Class[] constructorArgTypes) {
-        this(typeName, null, constructorArgNames, constructorArgTypes, null);
-    }
-
-    public ObjectRecipe(String typeName, String factoryMethod, String[] constructorArgNames, Class[] constructorArgTypes) {
-        this(typeName, factoryMethod, constructorArgNames, constructorArgTypes, null);
+        this(typeName, factoryMethod, null);
     }
 
-    public ObjectRecipe(String type, String factoryMethod, String[] constructorArgNames, Class[] constructorArgTypes, Map properties) {
+    private ObjectRecipe(String type, String factoryMethod, Map properties) {
         this.type = type;
         this.factoryMethod = factoryMethod;
         if (properties != null) {
@@ -122,6 +107,22 @@
         }
     }
 
+    public String getPostConstruct() {
+        return postConstruct;
+    }
+
+    public void setPostConstruct(String postConstruct) {
+        this.postConstruct = postConstruct;
+    }
+
+    public String getPreDestroy() {
+        return preDestroy;
+    }
+
+    public void setPreDestroy(String preDestroy) {
+        this.preDestroy = preDestroy;
+    }
+
     public Object create() throws ConstructionException {
         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
         return create(contextClassLoader);
@@ -147,6 +148,16 @@
             throw new ConstructionException("Class is abstract: " + ClassLoading.getClassName(typeClass, true));
         }
 
+        // get the PostConstruct method
+        Method postConstructMethod = null;
+        if (postConstruct != null) {
+            try {
+                postConstructMethod = typeClass.getMethod(postConstruct, null);
+            } catch (NoSuchMethodException e) {
+                throw new ConstructionException("Unable to find post construct method: " + postConstruct);
+            }
+        }
+
         // get object values for all recipe properties
         Map propertyValues = new LinkedHashMap(properties);
         for (Iterator iterator = propertyValues.entrySet().iterator(); iterator.hasNext();) {
@@ -174,59 +185,72 @@
             }
         }
 
-        Set requiredProperties = new HashSet(propertyValues.keySet());
-        requiredProperties.removeAll(setters.keySet());
+        // determine the properties that must be used
+        Map requiredProperties = new HashMap(propertyValues);
+        requiredProperties.keySet().removeAll(setters.keySet());
+
+        // get the factory
+        Factory factory = selectFactory(typeClass, requiredProperties);
+        if (factory == null) {
+            // todo use close match
+            throw new ConstructionException("Unable to find a constructor with properties: " + requiredProperties);
+        }
 
+        // remove the parameters from the propertyValues map
+        List parameters = removePropertyValues(factory, propertyValues);
 
         // create the instance
-        Object instance = createInstance(typeClass, requiredProperties, propertyValues);
-        if (instance == null) {
-            throw new ConstructionException("Unable to find a constructor with properties: " + requiredProperties);
-        }
+        Object instance = factory.create(parameters);
 
         // set remaining properties
         for (Iterator iterator = propertyValues.entrySet().iterator(); iterator.hasNext();) {
             Map.Entry entry = (Map.Entry) iterator.next();
             String propertyName = (String) entry.getKey();
+
+            Method setter = (Method) setters.get(propertyName);
+
             Object propertyValue = entry.getValue();
-            Method setter = findSetter(typeClass, propertyName, propertyValue);
+            propertyValue = convert(setter.getParameterTypes()[0], propertyValue);
+
             try {
-                propertyValue = convert(setter.getParameterTypes()[0], propertyValue);
                 setter.invoke(instance, new Object[]{propertyValue});
             } catch (Exception e) {
-                throw new ConstructionException("Error setting property: " + setter);
+                throw new ConstructionException("Error setting property: " + setter, e);
             }
         }
+
+        try {
+            postConstructMethod.invoke(instance, null);
+        } catch(Exception e) {
+            throw new ConstructionException("Error calling post construct method: " + postConstruct, e);
+        }
         return instance;
     }
 
-    private Object[] extractConstructorArgs(Map propertyValues, String[] constructorArgNames, Class[] constructorArgTypes) {
-        Object[] parameters = new Object[constructorArgNames.length];
-        for (int i = 0; i < constructorArgNames.length; i++) {
-            String name = constructorArgNames[i];
-            Class type = constructorArgTypes[i];
-
-            Object value;
-            if (propertyValues.containsKey(name)) {
-                value = propertyValues.remove(name);
-                if (!isInstance(type, value) && !isConvertable(type, value)) {
-                    throw new ConstructionException("Invalid and non-convertable constructor parameter type: " +
-                            "name=" + name + ", " +
-                            "index=" + i + ", " +
-                            "expected=" + ClassLoading.getClassName(type, true) + ", " +
-                            "actual=" + ClassLoading.getClassName(value, true));
-                }
-                value = convert(type, value);
-            } else {
-                value = getDefaultValue(type);
-            }
-
-
-            parameters[i] = value;
+    private List removePropertyValues(Factory factory, Map propertyValues) {
+        String[] parameterNames = factory.getParameterNames();
+        Class[] parameterTypes = factory.getParameterTypes();
+        List parameters = new ArrayList(parameterNames.length);
+        for (int i = 0; i < parameterNames.length; i++) {
+            String parameterName = parameterNames[i];
+            Class parameterType = parameterTypes[i];
+            Object value = removePropertyValue(propertyValues, parameterName, parameterType);
+            parameters.add(value);
         }
         return parameters;
     }
 
+    private Object removePropertyValue(Map propertyValues, String propertyName, Class propertyType) {
+        Object value;
+        if (propertyValues.containsKey(propertyName)) {
+            value = propertyValues.remove(propertyName);
+        } else {
+            value = getDefaultValue(propertyType);
+        }
+        value = convert(propertyType, value);
+        return value;
+    }
+
     private static Object convert(Class type, Object value) {
         if (value instanceof String && (type != Object.class)) {
             String stringValue = (String) value;
@@ -256,86 +280,73 @@
         return null;
     }
 
-    private Object createInstance(Class typeClass, Set requiredProperties, Map propertyValues) {
+    private Factory selectFactory(Class typeClass, Map requiredProperties) {
         if (factoryMethod != null) {
-            Method method = null;
-            String[] parameterNames = null;
+            SortedMap allMethodParameters = new TreeMap(ARGUMENT_LENGTH_COMPARATOR);
+            allMethodParameters.putAll(parameterNames.getAllMethodParameters(typeClass, factoryMethod));
 
-            Method[] methods = typeClass.getMethods();
-            Arrays.sort(methods, ARGUMENT_LENGTH_COMPARATOR);
-            for (int i = 0; i < methods.length; i++) {
-                Method m = methods[i];
-                if (m.getName().equals(factoryMethod)) {
-                    String[] names = ParameterNames.get(m);
-                    if (names != null && Arrays.asList(names).containsAll(requiredProperties)) {
-                        method = m;
-                        parameterNames = names;
-                        break;
-                    }
-                }
-            }
-            if (method == null) {
-                return null;
-            }
-
-            // get the constructor parameters
-            Object[] parameters = extractConstructorArgs(propertyValues, parameterNames, method.getParameterTypes());
+            CloseMatchException closeMatch = null;
+            for (Iterator iterator = allMethodParameters.entrySet().iterator(); iterator.hasNext();) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                Method method = (Method) entry.getKey();
+                String[] parameterNames = (String[]) entry.getValue();
 
-            try {
-                Object object = method.invoke(null, parameters);
-                return object;
-            } catch (Exception e) {
-                Throwable t = e;
-                if (e instanceof InvocationTargetException) {
-                    InvocationTargetException invocationTargetException = (InvocationTargetException) e;
-                    if (invocationTargetException.getCause() != null) {
-                        t = invocationTargetException.getCause();
+                if (parameterNames != null && Arrays.asList(parameterNames).containsAll(requiredProperties.keySet())) {
+                    Class[] propertyTypes = getPropertyTypes(parameterNames, requiredProperties);
+                    if (isAssignableFrom(method.getParameterTypes(), propertyTypes)) {
+                        CloseMatchException problem = checkFactory(method);
+                        if (problem == null) {
+                            return new FactoryMethodFactory(parameterNames, method);
+                        } else {
+                            closeMatch = CloseMatchException.greater(closeMatch, problem);
+                        }
+                    } else {
+                        closeMatch = CloseMatchException.greater(closeMatch, CloseMatchException.typeMismatch(method, parameterNames, propertyTypes));
                     }
+                } else {
+                    // todo remember most consuming method
                 }
-                throw new ConstructionException("Error invoking factory method: " + method, t);
             }
+            throw closeMatch;
         } else {
-            Constructor constructor = null;
-            String[] parameterNames = null;
-
-            Map map = ParameterNames.getAllConstructorParameters(typeClass);
-            SortedMap constructorArgs = new TreeMap(ARGUMENT_LENGTH_COMPARATOR);
-            constructorArgs.putAll(map);
+            SortedMap allConstructorParameters = new TreeMap(ARGUMENT_LENGTH_COMPARATOR);
+            allConstructorParameters.putAll(parameterNames.getAllConstructorParameters(typeClass));
 
-            for (Iterator iterator = constructorArgs.entrySet().iterator(); iterator.hasNext();) {
+            CloseMatchException closeMatch = null;
+            for (Iterator iterator = allConstructorParameters.entrySet().iterator(); iterator.hasNext();) {
                 Map.Entry entry = (Map.Entry) iterator.next();
-                Constructor c = (Constructor) entry.getKey();
-                String[] names = (String[]) entry.getValue();
-                if (names != null && Arrays.asList(names).containsAll(requiredProperties)) {
-                    constructor = c;
-                    parameterNames = names;
-                    break;
-                }
-            }
-            if (constructor == null) {
-                return null;
-            }
-
-            // get the constructor parameters
-            Object[] parameters = extractConstructorArgs(propertyValues, parameterNames, constructor.getParameterTypes());
+                Constructor constructor = (Constructor) entry.getKey();
+                String[] parameterNames = (String[]) entry.getValue();
 
-            try {
-                Object object = constructor.newInstance(parameters);
-                return object;
-            } catch (Exception e) {
-                Throwable t = e;
-                if (e instanceof InvocationTargetException) {
-                    InvocationTargetException invocationTargetException = (InvocationTargetException) e;
-                    if (invocationTargetException.getCause() != null) {
-                        t = invocationTargetException.getCause();
+                if (Arrays.asList(parameterNames).containsAll(requiredProperties.keySet())) {
+                    Class[] propertyTypes = getPropertyTypes(parameterNames, requiredProperties);
+                    if (isAssignableFrom(constructor.getParameterTypes(), propertyTypes)) {
+                        return new ConstructorFactory(parameterNames, constructor);
+                    } else {
+                        closeMatch = CloseMatchException.greater(closeMatch, CloseMatchException.typeMismatch(constructor, parameterNames, propertyTypes));
                     }
+                } else {
+                    // todo remember most consuming method
                 }
-                throw new ConstructionException("Error invoking constructor: " + constructor, t);
             }
+            throw closeMatch;
         }
     }
 
+    private Class[] getPropertyTypes(String[] propertyNames, Map properties) {
+        Class[] propertyTypes = new Class[propertyNames.length];
+        for (int i = 0; i < propertyNames.length; i++) {
+            String parameterName = propertyNames[i];
+            Object value = properties.get(parameterName);
+            if (value != null) {
+                propertyTypes[i] = value.getClass();
+            }
+        }
+        return propertyTypes;
+    }
+
     private static final ArgumentLengthComparator ARGUMENT_LENGTH_COMPARATOR = new ArgumentLengthComparator();
+
     private static class ArgumentLengthComparator implements Comparator {
         public int compare(Object left, Object right) {
             return getArgumentLength(left) - getArgumentLength(right);
@@ -343,169 +354,14 @@
 
         private int getArgumentLength(Object object) {
             if (object instanceof Method) {
-                return ((Method)object).getParameterTypes().length;
+                return ((Method) object).getParameterTypes().length;
             } else {
-                return ((Constructor)object).getParameterTypes().length;
+                return ((Constructor) object).getParameterTypes().length;
             }
         }
     }
-//    private Method selectFactory(Class typeClass, Set requiredProperties, Map propertyValues) {
-//        if (constructorArgNames.length > 0 && constructorArgTypes.length == 0) {
-//            ArrayList matches = new ArrayList();
-//
-//            Method[] methods = typeClass.getMethods();
-//            for (int i = 0; i < methods.length; i++) {
-//                Method method = methods[i];
-//                if (method.getName().equals(factoryMethod) && method.getParameterTypes().length == constructorArgNames.length) {
-//                    try {
-//                        checkFactory(method);
-//                        matches.add(method);
-//                    } catch (Exception dontCare) {
-//                    }
-//                }
-//            }
-//
-//            if (matches.size() < 1) {
-//                StringBuffer buffer = new StringBuffer("No parameter types supplied; unable to find a potentially valid factory method: ");
-//                buffer.append("public static Object ").append(factoryMethod);
-//                buffer.append(toArgumentList(constructorArgNames));
-//                throw new ConstructionException(buffer.toString());
-//            } else if (matches.size() > 1) {
-//                StringBuffer buffer = new StringBuffer("No parameter types supplied; found too many potentially valid factory methods: ");
-//                buffer.append("public static Object ").append(factoryMethod);
-//                buffer.append(toArgumentList(constructorArgNames));
-//                throw new ConstructionException(buffer.toString());
-//            }
-//
-//            return (Method) matches.get(0);
-//        }
-//
-//        try {
-//            Method method = typeClass.getMethod(factoryMethod, constructorArgTypes);
-//
-//            checkFactory(method);
-//
-//            return method;
-//        } catch (NoSuchMethodException e) {
-//            // try to find a matching private method
-//            Method[] methods = typeClass.getDeclaredMethods();
-//            for (int i = 0; i < methods.length; i++) {
-//                Method method = methods[i];
-//                if (method.getName().equals(factoryMethod) && isAssignableFrom(constructorArgTypes, method.getParameterTypes())) {
-//                    if (!Modifier.isPublic(method.getModifiers())) {
-//                        throw new ConstructionException("Factory method is not public: " + method);
-//                    }
-//                }
-//            }
-//
-//            StringBuffer buffer = new StringBuffer("Unable to find a valid factory method: ");
-//            buffer.append("public static Object ").append(ClassLoading.getClassName(typeClass, true)).append(".");
-//            buffer.append(factoryMethod).append(toParameterList(constructorArgTypes));
-//            throw new ConstructionException(buffer.toString());
-//        }
-//    }
-//
-//    private void checkFactory(Method method) {
-//        if (!Modifier.isPublic(method.getModifiers())) {
-//            // this will never occur since private methods are not returned from
-//            // getMethod, but leave this here anyway, just to be safe
-//            throw new ConstructionException("Factory method is not public: " + method);
-//        }
-//
-//        if (!Modifier.isStatic(method.getModifiers())) {
-//            throw new ConstructionException("Factory method is not static: " + method);
-//        }
-//
-//        if (method.getReturnType().equals(Void.TYPE)) {
-//            throw new ConstructionException("Factory method does not return anything: " + method);
-//        }
-//
-//        if (method.getReturnType().isPrimitive()) {
-//            throw new ConstructionException("Factory method returns a primitive type: " + method);
-//        }
-//    }
-//
-//    private Constructor selectConstructor(Class typeClass, Set requiredProperties, Map propertyValues) {
-//        if (constructorArgNames.length > 0 && constructorArgTypes.length == 0) {
-//            ArrayList matches = new ArrayList();
-//
-//            Constructor[] constructors = typeClass.getConstructors();
-//            for (int i = 0; i < constructors.length; i++) {
-//                Constructor constructor = constructors[i];
-//                if (constructor.getParameterTypes().length == constructorArgNames.length) {
-//                    matches.add(constructor);
-//                }
-//            }
-//
-//            if (matches.size() < 1) {
-//                StringBuffer buffer = new StringBuffer("No parameter types supplied; unable to find a potentially valid constructor: ");
-//                buffer.append("constructor= public ").append(ClassLoading.getClassName(typeClass, true));
-//                buffer.append(toArgumentList(constructorArgNames));
-//                throw new ConstructionException(buffer.toString());
-//            } else if (matches.size() > 1) {
-//                StringBuffer buffer = new StringBuffer("No parameter types supplied; found too many potentially valid constructors: ");
-//                buffer.append("constructor= public ").append(ClassLoading.getClassName(typeClass, true));
-//                buffer.append(toArgumentList(constructorArgNames));
-//                throw new ConstructionException(buffer.toString());
-//            }
-//
-//            return (Constructor) matches.get(0);
-//        }
-//
-//        try {
-//            Constructor constructor = typeClass.getConstructor(constructorArgTypes);
-//
-//            if (!Modifier.isPublic(constructor.getModifiers())) {
-//                // this will never occur since private constructors are not returned from
-//                // getConstructor, but leave this here anyway, just to be safe
-//                throw new ConstructionException("Constructor is not public: " + constructor);
-//            }
-//
-//            return constructor;
-//        } catch (NoSuchMethodException e) {
-//            // try to find a matching private method
-//            Constructor[] constructors = typeClass.getDeclaredConstructors();
-//            for (int i = 0; i < constructors.length; i++) {
-//                Constructor constructor = constructors[i];
-//                if (isAssignableFrom(constructorArgTypes, constructor.getParameterTypes())) {
-//                    if (!Modifier.isPublic(constructor.getModifiers())) {
-//                        throw new ConstructionException("Constructor is not public: " + constructor);
-//                    }
-//                }
-//            }
-//
-//            StringBuffer buffer = new StringBuffer("Unable to find a valid constructor: ");
-//            buffer.append("constructor= public ").append(ClassLoading.getClassName(typeClass, true));
-//            buffer.append(toParameterList(constructorArgTypes));
-//            throw new ConstructionException(buffer.toString());
-//        }
-//    }
-//
-//    private String toParameterList(Class[] parameterTypes) {
-//        StringBuffer buffer = new StringBuffer();
-//        buffer.append("(");
-//        for (int i = 0; i < parameterTypes.length; i++) {
-//            Class type = parameterTypes[i];
-//            if (i > 0) buffer.append(", ");
-//            buffer.append(ClassLoading.getClassName(type, true));
-//        }
-//        buffer.append(")");
-//        return buffer.toString();
-//    }
-//
-//    private String toArgumentList(String[] parameterNames) {
-//        StringBuffer buffer = new StringBuffer();
-//        buffer.append("(");
-//        for (int i = 0; i < parameterNames.length; i++) {
-//            String parameterName = parameterNames[i];
-//            if (i > 0) buffer.append(", ");
-//            buffer.append('<').append(parameterName).append('>');
-//        }
-//        buffer.append(")");
-//        return buffer.toString();
-//    }
 
-    public static Method findSetter(Class typeClass, String propertyName, Object propertyValue) {
+    private static Method findSetter(Class typeClass, String propertyName, Object propertyValue) {
         if (propertyName == null) throw new NullPointerException("name is null");
         if (propertyName.length() == 0) throw new IllegalArgumentException("name is an empty string");
 
@@ -581,7 +437,8 @@
                 }
 
 
-                if (!isInstance(methodParameterType, propertyValue) && !isConvertable(methodParameterType, propertyValue)) {
+                if (!isInstance(methodParameterType, propertyValue) && !isConvertable(methodParameterType, propertyValue))
+                {
                     if (matchLevel < 5) {
                         matchLevel = 5;
                         missException = new ConstructionException(ClassLoading.getClassName(propertyValue, true) + " can not be assigned or converted to " +
@@ -604,11 +461,33 @@
         }
     }
 
-    public static boolean isConvertable(Class methodParameterType, Object propertyValue) {
+    private CloseMatchException checkFactory(Method method) {
+        if (!Modifier.isPublic(method.getModifiers())) {
+            // this will never occur since private methods are not returned from
+            // getMethod, but leave this here anyway, just to be safe
+            return CloseMatchException.factoryMethodIsNotPublic(method);
+        }
+
+        if (!Modifier.isStatic(method.getModifiers())) {
+            return CloseMatchException.factoryMethodIsNotStatic(method);
+        }
+
+        if (method.getReturnType().equals(Void.TYPE)) {
+            return CloseMatchException.factoryMethodWithNoReturn(method);
+        }
+
+        if (method.getReturnType().isPrimitive()) {
+            return CloseMatchException.factoryMethodReturnsPrimitive(method);
+        }
+
+        return null;
+    }
+
+    private static boolean isConvertable(Class methodParameterType, Object propertyValue) {
         return (propertyValue instanceof String && PropertyEditors.canConvert(methodParameterType));
     }
 
-    public static boolean isInstance(Class type, Object instance) {
+    private static boolean isInstance(Class type, Object instance) {
         if (type.isPrimitive()) {
             // for primitives the insance can't be null
             if (instance == null) {
@@ -641,7 +520,13 @@
     }
 
     public static boolean isAssignableFrom(Class expected, Class actual) {
+        // if actual is null we are ok, since we can always use a default value
+        if (actual == null) return true;
+
         if (expected.isPrimitive()) {
+            // if actual is a String we are ok, since we can always have a converter to primitives
+            if (actual.equals(String.class)) return true;
+
             // verify actual is the correct wrapper type
             if (expected.equals(boolean.class)) {
                 return actual.equals(Boolean.class);
@@ -664,7 +549,11 @@
             }
         }
 
-        return expected.isAssignableFrom(actual);
+        // actual can be cast to expected
+        if (expected.isAssignableFrom(actual)) return true;
+
+        // if actual is a string and we have a property editory we are ok
+        return actual.equals(String.class) && PropertyEditors.canConvert(expected);
     }
 
     public static boolean isAssignableFrom(Class[] expectedTypes, Class[] actualTypes) {
@@ -680,4 +569,83 @@
         }
         return true;
     }
+
+    private static interface Factory {
+        Object create(List parameters);
+
+        String[] getParameterNames();
+
+        Class[] getParameterTypes();
+    }
+
+    private static class ConstructorFactory implements Factory {
+        private final String[] parameterNames;
+        private final Constructor constructor;
+
+        public ConstructorFactory(String[] parameterNames, Constructor constructor) {
+            this.parameterNames = parameterNames;
+            this.constructor = constructor;
+        }
+
+        public String[] getParameterNames() {
+            return parameterNames;
+        }
+
+        public Class[] getParameterTypes() {
+            return constructor.getParameterTypes();
+        }
+
+        public Object create(List parameters) {
+            Object[] parameterArray = parameters.toArray(new Object[parameters.size()]);
+            try {
+                Object object = constructor.newInstance(parameterArray);
+                return object;
+            } 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 invoking constructor: " + constructor, t);
+            }
+        }
+    }
+
+    private static class FactoryMethodFactory implements Factory {
+        private final String[] parameterNames;
+        private final Method factoryMethod;
+
+        public FactoryMethodFactory(String[] parameterNames, Method factoryMethod) {
+            this.parameterNames = parameterNames;
+            this.factoryMethod = factoryMethod;
+        }
+
+        public String[] getParameterNames() {
+            return parameterNames;
+        }
+
+        public Class[] getParameterTypes() {
+            return factoryMethod.getParameterTypes();
+        }
+
+        public Object create(List parameters) {
+            Object[] parameterArray = parameters.toArray(new Object[parameters.size()]);
+            try {
+                Object object = factoryMethod.invoke(null, parameterArray);
+                return object;
+            } 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 invoking factory method: " + factoryMethod, t);
+            }
+        }
+    }
+
 }

Added: geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/AsmParameterNames.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/AsmParameterNames.java?rev=407045&view=auto
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/AsmParameterNames.java (added)
+++ geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/AsmParameterNames.java Tue May 16 13:08:43 2006
@@ -0,0 +1,292 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation
+ *
+ *  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.apache.xbean.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.WeakHashMap;
+import java.util.Collections;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Implementation of ParameterNames that uses ASM to read the parameter names from the local variable table in the
+ * class byte code.
+ *
+ * This wonderful piece of code was taken from org.springframework.core.LocalVariableTableParameterNameDiscover
+ */
+public class AsmParameterNames implements ParameterNames {
+    /**
+     * Weak map from Constructor or Method to a String[].
+     */
+    private final WeakHashMap cache = new WeakHashMap();
+
+    /**
+     * Gets the parameter names of the specified method or null if the class was compiled without debug symbols on.
+     * @param method the method for which the parameter names should be retrieved
+     * @return the parameter names or null if the class was compilesd without debug symbols on
+     */
+    public String[] get(Method method) {
+        // check the cache
+        if (cache.containsKey(method)) {
+            return (String[]) cache.get(method);
+        }
+
+        Map allMethodParameters = getAllMethodParameters(method.getDeclaringClass(), method.getName());
+        return (String[]) allMethodParameters.get(method);
+    }
+
+    /**
+     * Gets the parameter names of the specified constructor or null if the class was compiled without debug symbols on.
+     * @param constructor the constructor for which the parameters should be retrieved
+     * @return the parameter names or null if the class was compiled without debug symbols on
+     */
+    public String[] get(Constructor constructor) {
+        // check the cache
+        if (cache.containsKey(constructor)) {
+            return (String[]) cache.get(constructor);
+        }
+
+        Map allConstructorParameters = getAllConstructorParameters(constructor.getDeclaringClass());
+        return (String[]) allConstructorParameters.get(constructor);
+    }
+
+    /**
+     * Gets the parameter names of all constructoror null if the class was compiled without debug symbols on.
+     * @param clazz the class for which the constructor parameter names should be retrieved
+     * @return a map from Constructor object to the parameter names or null if the class was compiled without debug symbols on
+     */
+    public Map getAllConstructorParameters(Class clazz) {
+        // Determine the constructors?
+        Constructor[] constructors = clazz.getConstructors();
+        if (constructors.length == 0) {
+            return Collections.EMPTY_MAP;
+        }
+
+        // Check the cache
+        if (cache.containsKey(constructors[0])) {
+            Map allParameterNames = new HashMap();
+            for (int i = 0; i < constructors.length; i++) {
+                Constructor constructor = constructors[i];
+                allParameterNames.put(constructor, cache.get(constructor));
+            }
+            return allParameterNames;
+        }
+
+        // Load the parameter names using ASM
+        Map allParameterNames = new HashMap();
+        try {
+            ClassReader reader = AsmParameterNames.createClassReader(clazz);
+
+            AsmParameterNames.AllParameterNamesDiscoveringVisitor visitor = new AsmParameterNames.AllParameterNamesDiscoveringVisitor(clazz);
+            reader.accept(visitor, false);
+
+            Map exceptions = visitor.getExceptions();
+            if (exceptions.size() == 1) {
+                throw new RuntimeException((Exception)exceptions.values().iterator().next());
+            }
+            if (!exceptions.isEmpty()) {
+                throw new RuntimeException(exceptions.toString());
+            }
+
+            allParameterNames = visitor.getAllParameterNames();
+        } catch (IOException ex) {
+        }
+
+        // Cache the names
+        for (int i = 0; i < constructors.length; i++) {
+            Constructor constructor = constructors[i];
+            cache.put(constructor, allParameterNames.get(constructor));
+        }
+        return allParameterNames;
+    }
+
+    /**
+     * Gets the parameter names of all methods with the specified name or null if the class was compiled without debug symbols on.
+     * @param clazz the class for which the method parameter names should be retrieved
+     * @param methodName the of the method for which the parameters should be retrieved
+     * @return a map from Method object to the parameter names or null if the class was compiled without debug symbols on
+     */
+    public Map getAllMethodParameters(Class clazz, String methodName) {
+        // Determine the constructors?
+        Method[] methods = getMethods(clazz, methodName);
+        if (methods.length == 0) {
+            return Collections.EMPTY_MAP;
+        }
+
+        // Check the cache
+        if (cache.containsKey(methods[0])) {
+            Map allParameterNames = new HashMap();
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                allParameterNames.put(method, cache.get(method));
+            }
+            return allParameterNames;
+        }
+
+        // Load the parameter names using ASM
+        Map allParameterNames = new HashMap();
+        try {
+            ClassReader reader = AsmParameterNames.createClassReader(clazz);
+
+            AsmParameterNames.AllParameterNamesDiscoveringVisitor visitor = new AsmParameterNames.AllParameterNamesDiscoveringVisitor(clazz, methodName);
+            reader.accept(visitor, false);
+
+            Map exceptions = visitor.getExceptions();
+            if (exceptions.size() == 1) {
+                throw new RuntimeException((Exception)exceptions.values().iterator().next());
+            }
+            if (!exceptions.isEmpty()) {
+                throw new RuntimeException(exceptions.toString());
+            }
+
+            allParameterNames = visitor.getAllParameterNames();
+        } catch (IOException ex) {
+        }
+
+        // Cache the names
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            cache.put(method, allParameterNames.get(method));
+        }
+        return allParameterNames;
+    }
+
+    private Method[] getMethods(Class clazz, String methodName) {
+        Method[] methods = clazz.getMethods();
+        List matchingMethod = new ArrayList(methods.length);
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            if (method.getName().equals(methodName)) {
+                matchingMethod.add(method);
+            }
+        }
+        return (Method[]) matchingMethod.toArray(new Method[matchingMethod.size()]);
+    }
+
+    private static ClassReader createClassReader(Class declaringClass) throws IOException {
+        InputStream in = null;
+        try {
+            ClassLoader classLoader = declaringClass.getClassLoader();
+            in = classLoader.getResourceAsStream(declaringClass.getName().replace('.', '/') + ".class");
+            ClassReader reader = new ClassReader(in);
+            return reader;
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ignored) {
+                }
+            }
+        }
+    }
+
+    private static class AllParameterNamesDiscoveringVisitor extends EmptyVisitor {
+        private final Map allParameterNames = new HashMap();
+        private final Map exceptions = new HashMap();
+        private final String methodName;
+        private final Map methodMap = new HashMap();
+
+        public AllParameterNamesDiscoveringVisitor(Class type, String methodName) {
+            this.methodName = methodName;
+
+            Method[] methods = type.getMethods();
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                if (method.getName().equals(methodName)) {
+                    methodMap.put(Type.getMethodDescriptor(method), method);
+                }
+            }
+        }
+
+        public AllParameterNamesDiscoveringVisitor(Class type) {
+            this.methodName = "<init>";
+
+            Constructor[] constructors = type.getConstructors();
+            for (int i = 0; i < constructors.length; i++) {
+                Constructor constructor = constructors[i];
+                Type[] types = new Type[constructor.getParameterTypes().length];
+                for (int j = 0; j < types.length; j++) {
+                    types[j] = Type.getType(constructor.getParameterTypes()[j]);
+                }
+                methodMap.put(Type.getMethodDescriptor(Type.VOID_TYPE, types), constructor);
+            }
+        }
+
+        public Map getAllParameterNames() {
+            return allParameterNames;
+        }
+
+        public Map getExceptions() {
+            return exceptions;
+        }
+
+        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+            if (!name.equals(this.methodName)) {
+                return null;
+            }
+
+            try {
+                final String[] parameterNames;
+                final boolean isStaticMethod;
+
+                if (methodName.equals("<init>")) {
+                    Constructor constructor = (Constructor) methodMap.get(desc);
+                    if (constructor == null) {
+                        return null;
+                    }
+                    parameterNames = new String[constructor.getParameterTypes().length];
+                    allParameterNames.put(constructor, parameterNames);
+                    isStaticMethod = false;
+                } else {
+                    Method method = (Method) methodMap.get(desc);
+                    if (method == null) {
+                        return null;
+                    }
+                    parameterNames = new String[method.getParameterTypes().length];
+                    allParameterNames.put(method, parameterNames);
+                    isStaticMethod = Modifier.isStatic(method.getModifiers());
+                }
+
+                return new EmptyVisitor() {
+                    // assume static method until we get a first parameter name
+                    public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
+                        if (isStaticMethod) {
+                            parameterNames[index] = name;
+                        } else if (index > 0) {
+                            parameterNames[(index -1)] = name;
+                        }
+                    }
+                };
+            } catch (Exception e) {
+                this.exceptions.put(signature, e);
+            }
+            return null;
+        }
+    }
+}

Modified: geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/ParameterNames.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/ParameterNames.java?rev=407045&r1=407044&r2=407045&view=diff
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/ParameterNames.java (original)
+++ geronimo/xbean/branches/xbean-reflect-args/src/main/java/org/apache/xbean/util/ParameterNames.java Tue May 16 13:08:43 2006
@@ -20,8 +20,8 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.Map;
 import java.util.HashMap;
+import java.util.Map;
 
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.Label;
@@ -30,77 +30,29 @@
 import org.objectweb.asm.commons.EmptyVisitor;
 
 /**
- * Implementation of ParameterNameDiscover that uses the
- * LocalVariableTable information in the method attributes
- * to discover parameter names.
- * <p/>
- * Returns null if the class file was compiled without debug
- * information.
- *
- * This wonderful piece of code was taken from org.springframework.core.LocalVariableTableParameterNameDiscover
- *
- * @author Adrian Colyer
- * @since 2.0
+ * Determines the parameter names of Constructors or Methods.
  */
-public final class ParameterNames {
+public interface ParameterNames {
     /**
      * Gets the parameter names of the specified method or null if the class was compiled without debug symbols on.
      * @param method the method for which the parameter names should be retrieved
      * @return the parameter names or null if the class was compilesd without debug symbols on
      */
-    public static String[] get(Method method) {
-        try {
-            Class declaringClass = method.getDeclaringClass();
-            ClassReader reader = createClassReader(declaringClass);
-            ParameterNameDiscoveringVisitor visitor = new ParameterNameDiscoveringVisitor(method);
-            reader.accept(visitor, false);
-            return visitor.getParameterNames();
-        } catch (IOException ex) {
-        }
-        return null;
-    }
+    String[] get(Method method);
 
     /**
      * Gets the parameter names of the specified constructor or null if the class was compiled without debug symbols on.
      * @param constructor the constructor for which the parameters should be retrieved
      * @return the parameter names or null if the class was compiled without debug symbols on
      */
-    public static String[] get(Constructor constructor) {
-        try {
-            Class declaringClass = constructor.getDeclaringClass();
-            ClassReader reader = createClassReader(declaringClass);
-            ParameterNameDiscoveringVisitor visitor = new ParameterNameDiscoveringVisitor(constructor);
-            reader.accept(visitor, false);
-            return visitor.getParameterNames();
-        } catch (IOException ex) {
-        }
-        return null;
-    }
+    String[] get(Constructor constructor);
 
     /**
      * Gets the parameter names of all constructoror null if the class was compiled without debug symbols on.
      * @param clazz the class for which the constructor parameter names should be retrieved
      * @return a map from Constructor object to the parameter names or null if the class was compiled without debug symbols on
      */
-    public static Map getAllConstructorParameters(Class clazz) {
-        // todo this should be done with a single pass though the class
-        try {
-            ClassReader reader = createClassReader(clazz);
-
-            HashMap nameMap = new HashMap();
-            Constructor[] constructors = clazz.getConstructors();
-            for (int i = 0; i < constructors.length; i++) {
-                Constructor constructor = constructors[i];
-                ParameterNameDiscoveringVisitor visitor = new ParameterNameDiscoveringVisitor(constructor);
-                reader.accept(visitor, false);
-                String[] parameterNames = visitor.getParameterNames();
-                nameMap.put(constructor, parameterNames);
-            }
-            return nameMap;
-        } catch (IOException ex) {
-        }
-        return null;
-    }
+    Map getAllConstructorParameters(Class clazz);
 
     /**
      * Gets the parameter names of all methods with the specified name or null if the class was compiled without debug symbols on.
@@ -108,93 +60,5 @@
      * @param methodName the of the method for which the parameters should be retrieved
      * @return a map from Method object to the parameter names or null if the class was compiled without debug symbols on
      */
-    public static Map getAllMethodParameters(Class clazz, String methodName) {
-        // todo this should be done with a single pass though the class
-        try {
-            ClassReader reader = createClassReader(clazz);
-
-            HashMap nameMap = new HashMap();
-            Method[] methods = clazz.getMethods();
-            for (int i = 0; i < methods.length; i++) {
-                Method method = methods[i];
-                if (method.getName().equals(methodName)) {
-                    ParameterNameDiscoveringVisitor visitor = new ParameterNameDiscoveringVisitor(method);
-                    reader.accept(visitor, false);
-                    String[] parameterNames = visitor.getParameterNames();
-                    nameMap.put(method, parameterNames);
-                }
-            }
-            return nameMap;
-        } catch (IOException ex) {
-        }
-        return null;
-    }
-
-    private static ClassReader createClassReader(Class declaringClass) throws IOException {
-        InputStream in = null;
-        try {
-            ClassLoader classLoader = declaringClass.getClassLoader();
-            in = classLoader.getResourceAsStream(declaringClass.getName().replace('.', '/') + ".class");
-            ClassReader reader = new ClassReader(in);
-            return reader;
-        } finally {
-            if (in != null) {
-                try {
-                    in.close();
-                } catch (IOException ignored) {
-                }
-            }
-        }
-    }
-
-    private static class ParameterNameDiscoveringVisitor extends EmptyVisitor {
-        private final String methodName;
-        private final boolean isStaticMethod;
-        private final String[] parameterNames;
-        private final String descriptor;
-
-        public ParameterNameDiscoveringVisitor(Method method) {
-            this.methodName = method.getName();
-            this.isStaticMethod = Modifier.isStatic(method.getModifiers());
-            this.parameterNames = new String[method.getParameterTypes().length];
-            this.descriptor = Type.getMethodDescriptor(method);
-        }
-
-        public ParameterNameDiscoveringVisitor(Constructor constructor) {
-            this.methodName = "<init>";
-            this.isStaticMethod = false;
-            this.parameterNames = new String[constructor.getParameterTypes().length];
-
-            Type[] pTypes = new Type[constructor.getParameterTypes().length];
-            for (int i = 0; i < pTypes.length; i++) {
-                pTypes[i] = Type.getType(constructor.getParameterTypes()[i]);
-            }
-            this.descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, pTypes);
-        }
-
-        public String[] getParameterNames() {
-            // if we didn't find the method or if the class was not compiled
-            // with debug symbols the parameter names will null
-            if (parameterNames[0] == null) {
-                return null;
-            }
-
-            return parameterNames;
-        }
-
-        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
-            if (!name.equals(this.methodName) || !desc.equals(this.descriptor)) {
-                return null;
-            }
-            return new EmptyVisitor() {
-                public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
-                    if (isStaticMethod) {
-                        parameterNames[index] = name;
-                    } else if (index > 0) {
-                        parameterNames[(index -1)] = name;
-                    }
-                }
-            };
-        }
-    }
+    Map getAllMethodParameters(Class clazz, String methodName);
 }

Modified: geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java?rev=407045&r1=407044&r2=407045&view=diff
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java (original)
+++ geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java Tue May 16 13:08:43 2006
@@ -12,6 +12,7 @@
 public class ObjectRecipeTest extends TestCase {
 
     protected void setUp() throws Exception {
+        super.setUp();
         PropertyEditors.class.getName();
     }
 
@@ -22,7 +23,6 @@
     }
 
     public void testConstructor() throws Exception {
-
         ObjectRecipe objectRecipe = new ObjectRecipe(Person.class);
         doTest(objectRecipe);
     }
@@ -43,9 +43,11 @@
         objectRecipe.setProperty("name", "Joe");
         objectRecipe.setProperty("age", "21");
         objectRecipe.setProperty("homePage", "http://www.acme.org");
+        objectRecipe.setPostConstruct("start");
 
         Person actual = (Person) objectRecipe.create(Person.class.getClassLoader());
         assertEquals("person", expected, actual);
+        assertTrue(actual.wasStarted());
     }
 
 }

Modified: geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/Person.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/Person.java?rev=407045&r1=407044&r2=407045&view=diff
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/Person.java (original)
+++ geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/recipe/Person.java Tue May 16 13:08:43 2006
@@ -26,13 +26,7 @@
     private String name;
     private int age;
     private URL homePage;
-
-//    public Person() {
-//    }
-
-//    private Person(String name) {
-//        this.name = name;
-//    }
+    private boolean started;
 
     public Person(String name, int age, URL homePage) {
         this.name = name;
@@ -40,10 +34,6 @@
         this.homePage = homePage;
     }
 
-//    public static Person newInstance(){
-//        return new Person();
-//    }
-
     public static Person newInstance(String name, int age, URL homePage){
         return new Person(name, age, homePage);        
     }
@@ -60,10 +50,6 @@
         return name;
     }
 
-//    public void setName(String name) {
-//        this.name = name;
-//    }
-
     public int getAge() {
         return age;
     }
@@ -78,6 +64,14 @@
 
     public void setHomePage(URL homePage) {
         this.homePage = homePage;
+    }
+
+    public void start() {
+        started = true;
+    }
+
+    public boolean wasStarted() {
+        return started;
     }
 
     public String toString() {

Modified: geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/util/ParameterNamesTest.java
URL: http://svn.apache.org/viewcvs/geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/util/ParameterNamesTest.java?rev=407045&r1=407044&r2=407045&view=diff
==============================================================================
--- geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/util/ParameterNamesTest.java (original)
+++ geronimo/xbean/branches/xbean-reflect-args/src/test/java/org/apache/xbean/util/ParameterNamesTest.java Tue May 16 13:08:43 2006
@@ -31,6 +31,7 @@
  * @version $Rev$ $Date$
  */
 public class ParameterNamesTest extends TestCase {
+    private final ParameterNames parameterNames = new AsmParameterNames();
     public void testConstructor() throws Exception {
         Constructor constructor = TestClass.class.getConstructor(new Class[] {int.class, Object.class, Long.class});
         assertParameterNames(new String[] {"one", "two", "three"}, constructor);
@@ -53,12 +54,12 @@
 
     public void testPrivateConstructor() throws Exception {
         Constructor constructor = findPrivateConstructor(TestClass.class, new Class[]{Double.class});
-        assertParameterNames(new String[] {"scotch"}, constructor);
+        assertNull(parameterNames.get(constructor));
     }
 
     public void testPrivateMethod() throws Exception {
         Method method = findPrivateMethod(TestClass.class, "factoryMethod", new Class[] {Double.class});
-        assertParameterNames(new String[] {"shot"}, method);
+        assertNull(parameterNames.get(method));
     }
 
     public void testAllConstructors() throws Exception {
@@ -66,8 +67,9 @@
         expectedMap.put(TestClass.class.getConstructor(new Class[] {int.class, Object.class, Long.class}),new String[] {"one", "two", "three"});
         expectedMap.put(TestClass.class.getConstructor(new Class[] {int.class}),new String[] {"foo"});
         expectedMap.put(TestClass.class.getConstructor(new Class[] {Object.class}),new String[] {"bar"});
+        expectedMap.put(TestClass.class.getConstructor(new Class[] {Object[].class}),new String[] {"objectArray"});
 
-        Map actualMap = ParameterNames.getAllConstructorParameters(TestClass.class);
+        Map actualMap = parameterNames.getAllConstructorParameters(TestClass.class);
         assertEquals(expectedMap, actualMap);
     }
 
@@ -77,7 +79,7 @@
         expectedMap.put(TestClass.class.getMethod("instanceMethod", new Class[] {int.class}), new String[] {"apple"});
         expectedMap.put(TestClass.class.getMethod("instanceMethod", new Class[] {Object.class}), new String[] {"ipod"});
 
-        Map actualMap = ParameterNames.getAllMethodParameters(TestClass.class, "instanceMethod");
+        Map actualMap = parameterNames.getAllMethodParameters(TestClass.class, "instanceMethod");
         assertEquals(expectedMap, actualMap);
     }
 
@@ -87,7 +89,7 @@
         expectedMap.put(TestClass.class.getMethod("factoryMethod", new Class[] {int.class}), new String[] {"beer"});
         expectedMap.put(TestClass.class.getMethod("factoryMethod", new Class[] {Object.class}), new String[] {"pizza"});
 
-        Map actualMap = ParameterNames.getAllMethodParameters(TestClass.class, "factoryMethod");
+        Map actualMap = parameterNames.getAllMethodParameters(TestClass.class, "factoryMethod");
         assertEquals(expectedMap, actualMap);
     }
 
@@ -96,7 +98,7 @@
         expectedMap.put(TestClass.class.getMethod("mixedMethods", new Class[] {Double.class}), new String[] {"gin"});
         expectedMap.put(TestClass.class.getMethod("mixedMethods", new Class[] {Short.class}), new String[] {"tonic"});
 
-        Map actualMap = ParameterNames.getAllMethodParameters(TestClass.class, "mixedMethods");
+        Map actualMap = parameterNames.getAllMethodParameters(TestClass.class, "mixedMethods");
         assertEquals(expectedMap, actualMap);
     }
 
@@ -108,6 +110,7 @@
         public TestClass(int one, Object two, Long three) {}
         public TestClass(int foo) {}
         public TestClass(Object bar) {}
+        public TestClass(Object[] objectArray) {}
         private TestClass(Double scotch) {}
 
         public static void factoryMethod(int a, Object b, Long c) {}
@@ -126,13 +129,13 @@
         public abstract void abstractMethod(Byte ear);
     }
 
-    private static void assertParameterNames(String[] expectedNames, Constructor constructor) {
-        String[] actualNames = ParameterNames.get(constructor);
+    private void assertParameterNames(String[] expectedNames, Constructor constructor) {
+        String[] actualNames = parameterNames.get(constructor);
         assertEquals(expectedNames, actualNames);
     }
 
-    private static void assertParameterNames(String[] expectedNames, Method method) {
-        String[] actualNames = ParameterNames.get(method);
+    private void assertParameterNames(String[] expectedNames, Method method) {
+        String[] actualNames = parameterNames.get(method);
         assertEquals(expectedNames, actualNames);
     }