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);
}