Here is some code I've been twiddling with to try and lazily fill in fields in object, mostly for object factories in JUnit but it could be quite a useful method to have.
private void lazyObjectFill(Object 开发者_Go百科profil) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
final Method[] list = profil.getClass().getDeclaredMethods();
for (Method m : list) {
if (Modifier.isPublic(m.getModifiers()) && m.getName().startsWith("set")) {
final Class< ?>[] parameterTypes = m.getParameterTypes();
if (parameterTypes.length == 1) {
final Class< ?> clazz = parameterTypes[0];
if (clazz == String.class) {
log.info("Invoking " + m.getName() + " with [\"\"]");
m.invoke("");
} else if (clazz.isPrimitive() && Defaults.defaultValue(clazz) != null) {
log.info("Invoking " + m.getName() + " with [" + Defaults.defaultValue(clazz) + "]");
m.invoke(Defaults.defaultValue(clazz));
}
}
}
}
}
We get the following exception when running this code on an object.
java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:592)
The exception occurs when running m.invoke(""); on a string setter.
Updated source code for the benefit of the googlers.
private void lazyObjectFill(Object obj) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
final Method[] list = obj.getClass().getDeclaredMethods();
for (Method method : list) {
method.setAccessible(true);
if (Modifier.isPublic(method.getModifiers()) && method.getName().startsWith("set")) {
final Class< ?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
final Class< ?> clazz = parameterTypes[0];
if (clazz == String.class) {
log.info("Invoking " + method.getName() + " with [\"\"]");
method.invoke(obj, "");
} else if (clazz.isPrimitive() && Defaults.defaultValue(clazz) != null) {
log.info("Invoking " + method.getName() + " with [" + Defaults.defaultValue(clazz) + "]");
method.invoke(obj, Defaults.defaultValue(clazz));
}
}
}
}
}
You are almost there, but methods are static and they need an object on which to invoke them.
i.e.
m.invoke(profil, "");
and
m.invoke(profil, Defaults.defaultValue(clazz));
You were (unknowingly) trying to execute the method on a string object without parameters. And since the string class does not have that method, it had to fail. Details can be found in the Method javadoc.
BTW: Static methods are invoked like this:
method.invoke(null, params);
You know that invoke method of Method takes two arguments ? As a consequence, I guess you wrote
m.invoke(profil, "")
Besides, I would personnally not have separated String from other objects.
And finally, to correctly identify obejct fields, i would have preferred a mixed approach
- Use an enumeration of non static Field members
- Use BeanInfo to access bean properties.
The first parameter of the Method.invoke()
is the object which will invoke the method.
For example in your case m.invoke(profil, "");
or m.invoke(profil, Defaults.defaultValue(clazz));
精彩评论