Modify the reflection utility to be able to recognize property of type object and setter with string param.

git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@417699 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Adrian T. Co 2006-06-28 08:44:29 +00:00
parent faff4999f4
commit 0dbcc1f4af
3 changed files with 158 additions and 120 deletions

View File

@ -23,10 +23,9 @@ import java.util.StringTokenizer;
import java.util.Properties; import java.util.Properties;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
public final class ReflectionUtil { public final class ReflectionUtil {
private static final Log log = LogFactory.getLog(ReflectionUtil.class); private static final Log log = LogFactory.getLog(ReflectionUtil.class);
@ -47,7 +46,7 @@ public final class ReflectionUtil {
StringTokenizer tokenizer = new StringTokenizer(key, "."); StringTokenizer tokenizer = new StringTokenizer(key, ".");
int tokenCount = tokenizer.countTokens(); int tokenCount = tokenizer.countTokens();
// For nested settings, get the object first. -2, do not count the first and last token // For nested settings, get the object first. -1, do not count the last token
for (int j=0; j<tokenCount-1; j++) { for (int j=0; j<tokenCount-1; j++) {
// Find getter method first // Find getter method first
String name = tokenizer.nextToken(); String name = tokenizer.nextToken();
@ -67,43 +66,46 @@ public final class ReflectionUtil {
return; return;
} }
// Determine data type of property // Find setter method
Class propertyType = getField(targetClass, property).getType(); Method setterMethod = findSetterMethod(targetClass, property);
// Get setter method // Get the first parameter type. This assumes that there is only one parameter.
String setterMethod = "set" + property.substring(0,1).toUpperCase() + property.substring(1); if (setterMethod == null) {
throw new IllegalAccessException("Unable to find appropriate setter method signature for property: " + property);
}
Class paramType = setterMethod.getParameterTypes()[0];
// Set primitive type // Set primitive type
debugInfo += ("." + setterMethod + "(" + propertyType.getName() + ": " + val + ")"); debugInfo += ("." + setterMethod + "(" + paramType.getName() + ": " + val + ")");
if (propertyType.isPrimitive()) { if (paramType.isPrimitive()) {
if (propertyType == Boolean.TYPE) { if (paramType == Boolean.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {boolean.class}).invoke(target, new Object[] {Boolean.valueOf(val)}); setterMethod.invoke(target, new Object[] {Boolean.valueOf(val)});
} else if (propertyType == Integer.TYPE) { } else if (paramType == Integer.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {int.class}).invoke(target, new Object[] {Integer.valueOf(val)}); setterMethod.invoke(target, new Object[] {Integer.valueOf(val)});
} else if (propertyType == Long.TYPE) { } else if (paramType == Long.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {long.class}).invoke(target, new Object[] {Long.valueOf(val)}); setterMethod.invoke(target, new Object[] {Long.valueOf(val)});
} else if (propertyType == Double.TYPE) { } else if (paramType == Double.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {double.class}).invoke(target, new Object[] {Double.valueOf(val)}); setterMethod.invoke(target, new Object[] {Double.valueOf(val)});
} else if (propertyType == Float.TYPE) { } else if (paramType == Float.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {float.class}).invoke(target, new Object[] {Float.valueOf(val)}); setterMethod.invoke(target, new Object[] {Float.valueOf(val)});
} else if (propertyType == Short.TYPE) { } else if (paramType == Short.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {short.class}).invoke(target, new Object[] {Short.valueOf(val)}); setterMethod.invoke(target, new Object[] {Short.valueOf(val)});
} else if (propertyType == Byte.TYPE) { } else if (paramType == Byte.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {byte.class}).invoke(target, new Object[] {Byte.valueOf(val)}); setterMethod.invoke(target, new Object[] {Byte.valueOf(val)});
} else if (propertyType == Character.TYPE) { } else if (paramType == Character.TYPE) {
targetClass.getMethod(setterMethod, new Class[] {char.class}).invoke(target, new Object[] {new Character(val.charAt(0))}); setterMethod.invoke(target, new Object[] {new Character(val.charAt(0))});
} }
} else { } else {
// Set String type // Set String type
if (propertyType == String.class) { if (paramType == String.class) {
targetClass.getMethod(setterMethod, new Class[] {String.class}).invoke(target, new Object[] {val}); setterMethod.invoke(target, new Object[] {val});
// For unknown object type, try to call the valueOf method of the object // For unknown object type, try to create an instance of the object using a String constructor
// to convert the string to the target object type
} else { } else {
// Note valueOf method should be public and static Constructor c = paramType.getConstructor(new Class[] {String.class});
Object param = propertyType.getMethod("valueOf", new Class[] {String.class}).invoke(null, new Object[] {val}); Object paramObject = c.newInstance(new Object[] {val});
targetClass.getMethod(setterMethod, new Class[] {propertyType}).invoke(target, new Object[] {param});
setterMethod.invoke(target, new Object[] {paramObject});
} }
} }
log.debug(debugInfo); log.debug(debugInfo);
@ -142,26 +144,31 @@ public final class ReflectionUtil {
return new Properties(); return new Properties();
} else { } else {
Properties props = new Properties(); Properties props = new Properties();
Field[] fields = getAllFields(targetClass); Method[] getterMethods = findAllGetterMethods(targetClass);
Method getterMethod; for (int i=0; i<getterMethods.length; i++) {
for (int i=0; i<fields.length; i++) {
try { try {
if ((getterMethod = isPropertyField(targetClass, fields[i])) != null) { String propertyName = getPropertyName(getterMethods[i].getName());
if (fields[i].getType().isPrimitive() || fields[i].getType() == String.class) { Class retType = getterMethods[i].getReturnType();
// If primitive or string type, return it
if (retType.isPrimitive() || retType == String.class) {
// Check for an appropriate setter method to consider it as a property
if (findSetterMethod(targetClass, propertyName) != null) {
Object val = null; Object val = null;
try { try {
val = getterMethod.invoke(targetObject, null); val = getterMethods[i].invoke(targetObject, null);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }
props.setProperty(prefix + fields[i].getName(), val + ""); props.setProperty(prefix + propertyName, val + "");
}
} else { } else {
try { try {
Object val = getterMethod.invoke(targetObject, null); Object val = getterMethods[i].invoke(targetObject, null);
if (val != null) { if (val != null) {
props.putAll(retrieveClassProperties(fields[i].getName() + ".", val.getClass(), val)); props.putAll(retrieveClassProperties(propertyName + ".", val.getClass(), val));
} }
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
@ -169,7 +176,6 @@ public final class ReflectionUtil {
e.printStackTrace(); e.printStackTrace();
} }
} }
}
} catch (Throwable t) { } catch (Throwable t) {
// Let's catch any exception, cause this could be cause by the foreign class // Let's catch any exception, cause this could be cause by the foreign class
t.printStackTrace(); t.printStackTrace();
@ -179,48 +185,91 @@ public final class ReflectionUtil {
} }
} }
protected static Method isPropertyField(Class targetClass, Field targetField) { private static Method findSetterMethod(Class targetClass, String propertyName) {
String fieldName = targetField.getName(); String methodName = "set" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
String getMethod = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
String isMethod = "is" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
String setMethod = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
// Check setter method Method[] methods = targetClass.getMethods();
for (int i=0; i<methods.length; i++) {
if (methods[i].getName().equals(methodName) && isSetterMethod(methods[i])) {
return methods[i];
}
}
return null;
}
private static Method findGetterMethod(Class targetClass, String propertyName) {
String methodName1 = "get" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
String methodName2 = "is" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
Method[] methods = targetClass.getMethods();
for (int i=0; i<methods.length; i++) {
if ((methods[i].getName().equals(methodName1) || methods[i].getName().equals(methodName2)) && isGetterMethod(methods[i])) {
return methods[i];
}
}
return null;
}
private static Method[] findAllGetterMethods(Class targetClass) {
List getterMethods = new ArrayList();
Method[] methods = targetClass.getMethods();
for (int i=0; i<methods.length; i++) {
if (isGetterMethod(methods[i])) {
getterMethods.add(methods[i]);
}
}
return (Method[])getterMethods.toArray(new Method[] {});
}
private static boolean isGetterMethod(Method method) {
// Check method signature first
// If 'get' method, must return a non-void value
// If 'is' method, must return a boolean value
// Both must have no parameters
// Method must not belong to the Object class to prevent infinite loop
return (((method.getName().startsWith("is") && method.getReturnType() == Boolean.TYPE) ||
(method.getName().startsWith("get") && method.getReturnType() != Void.TYPE)) &&
(method.getParameterTypes().length == 0) && method.getDeclaringClass() != Object.class);
}
private static boolean isSetterMethod(Method method) {
// Check method signature first
if (method.getName().startsWith("set") && method.getReturnType() == Void.TYPE) {
Class[] paramType = method.getParameterTypes();
// Check that it can only accept one parameter
if (paramType.length == 1) {
// Check if parameter is a primitive or can accept a String parameter
if (paramType[0].isPrimitive() || paramType[0] == String.class) {
return true;
} else {
// Check if object can accept a string as a constructor
try { try {
targetClass.getMethod(setMethod, new Class[]{targetField.getType()}); if (paramType[0].getConstructor(new Class[] {String.class}) != null) {
return true;
}
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
return null; // Do nothing
}
}
}
}
return false;
} }
// Check getter method and return it if it exists private static String getPropertyName(String methodName) {
try { String name;
return targetClass.getMethod(getMethod, null); if (methodName.startsWith("get")) {
} catch (NoSuchMethodException e1) { name = methodName.substring(3);
try { } else if (methodName.startsWith("set")) {
return targetClass.getMethod(isMethod, null); name = methodName.substring(3);
} catch (NoSuchMethodException e2) { } else if (methodName.startsWith("is")) {
return null; name = methodName.substring(2);
} } else {
} name = "";
} }
public static Field getField(Class targetClass, String fieldName) throws NoSuchFieldException { return name.substring(0,1).toLowerCase() + name.substring(1);
while (targetClass != null) {
try {
return targetClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
targetClass = targetClass.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
public static Field[] getAllFields(Class targetClass) {
List fieldList = new ArrayList();
while (targetClass != null) {
fieldList.addAll(Arrays.asList(targetClass.getDeclaredFields()));
targetClass = targetClass.getSuperclass();
}
return (Field[])fieldList.toArray(new Field[0]);
} }
} }

View File

@ -52,7 +52,6 @@ public abstract class ClassLoaderSPIConnectionFactory implements SPIConnectionFa
try { try {
File f = new File(dir); File f = new File(dir);
dir = f.getAbsolutePath(); dir = f.getAbsolutePath();
System.out.println(dir);
urls.add(f.toURL()); urls.add(f.toURL());
File[] files = f.listFiles(); File[] files = f.listFiles();
@ -71,7 +70,7 @@ public abstract class ClassLoaderSPIConnectionFactory implements SPIConnectionFa
URL u[] = new URL[urls.size()]; URL u[] = new URL[urls.size()];
urls.toArray(u); urls.toArray(u);
return new URLClassLoader(u, ClassLoaderSPIConnectionFactory.class.getClassLoader()); return new URLClassLoader(u, Thread.currentThread().getContextClassLoader());
} }
return ClassLoaderSPIConnectionFactory.class.getClassLoader(); return ClassLoaderSPIConnectionFactory.class.getClassLoader();
} }

View File

@ -19,12 +19,11 @@ package org.apache.activemq.tool;
import junit.framework.TestCase; import junit.framework.TestCase;
import java.util.Properties; import java.util.Properties;
import java.io.File;
import org.apache.activemq.tool.properties.ReflectionUtil; import org.apache.activemq.tool.properties.ReflectionUtil;
public class ReflectionUtilTest extends TestCase { public class ReflectionUtilTest extends TestCase {
private ReflectionUtilTest testData;
private String data;
public void testDataTypeConfig() { public void testDataTypeConfig() {
TestClass3 targetObj = new TestClass3(); TestClass3 targetObj = new TestClass3();
@ -67,11 +66,11 @@ public class ReflectionUtilTest extends TestCase {
} }
public void testValueOfMethod() { public void testValueOfMethod() {
ReflectionUtilTest targetObj = new ReflectionUtilTest(); TestClass4 targetObj = new TestClass4();
ReflectionUtil.configureClass(targetObj, "testData", "TEST.FOO.BAR"); ReflectionUtil.configureClass(targetObj, "testFile", "TEST.FOO.BAR");
assertEquals("TEST.FOO.BAR", targetObj.testData.data); assertEquals("TEST.FOO.BAR", targetObj.testFile.toString());
} }
public void testGetProperties() { public void testGetProperties() {
@ -100,15 +99,6 @@ public class ReflectionUtilTest extends TestCase {
targetObj.setTestData(testData); targetObj.setTestData(testData);
Properties p = ReflectionUtil.retrieveObjectProperties(targetObj); Properties p = ReflectionUtil.retrieveObjectProperties(targetObj);
assertEquals("false", p.getProperty("testData.booleanData"));
assertEquals("15", p.getProperty("testData.byteData"));
assertEquals("G", p.getProperty("testData.charData"));
assertEquals("765.43", p.getProperty("testData.doubleData"));
assertEquals("543.21", p.getProperty("testData.floatData"));
assertEquals("654321", p.getProperty("testData.intData"));
assertEquals("987654321", p.getProperty("testData.longData"));
assertEquals("4321", p.getProperty("testData.shortData"));
assertEquals("BAR.TEST.FOO", p.getProperty("testData.stringData"));
assertEquals("true", p.getProperty("booleanData")); assertEquals("true", p.getProperty("booleanData"));
assertEquals("10", p.getProperty("byteData")); assertEquals("10", p.getProperty("byteData"));
assertEquals("D", p.getProperty("charData")); assertEquals("D", p.getProperty("charData"));
@ -118,6 +108,16 @@ public class ReflectionUtilTest extends TestCase {
assertEquals("1234567890", p.getProperty("longData")); assertEquals("1234567890", p.getProperty("longData"));
assertEquals("1234", p.getProperty("shortData")); assertEquals("1234", p.getProperty("shortData"));
assertEquals("Test.FOO.BAR", p.getProperty("stringData")); assertEquals("Test.FOO.BAR", p.getProperty("stringData"));
assertEquals("false", p.getProperty("testData.booleanData"));
assertEquals("15", p.getProperty("testData.byteData"));
assertEquals("G", p.getProperty("testData.charData"));
assertEquals("765.43", p.getProperty("testData.doubleData"));
assertEquals("543.21", p.getProperty("testData.floatData"));
assertEquals("654321", p.getProperty("testData.intData"));
assertEquals("987654321", p.getProperty("testData.longData"));
assertEquals("4321", p.getProperty("testData.shortData"));
assertEquals("BAR.TEST.FOO", p.getProperty("testData.stringData"));
} }
public void testNestedConfig() { public void testNestedConfig() {
@ -147,28 +147,6 @@ public class ReflectionUtilTest extends TestCase {
assertEquals("t5", t5.getStringData()); assertEquals("t5", t5.getStringData());
} }
public static ReflectionUtilTest valueOf(String data) {
ReflectionUtilTest test = new ReflectionUtilTest();
test.data = data;
return test;
}
public ReflectionUtilTest getTestData() {
return testData;
}
public void setTestData(ReflectionUtilTest testData) {
this.testData = testData;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public class TestClass1 { public class TestClass1 {
private boolean booleanData; private boolean booleanData;
private int intData; private int intData;
@ -267,4 +245,16 @@ public class ReflectionUtilTest extends TestCase {
this.testData = testData; this.testData = testData;
} }
} }
public class TestClass4 {
private File testFile;
public String getTestFile() {
return testFile.toString();
}
public void setTestFile(String testFile) {
this.testFile = new File(testFile);
}
}
} }