开发者

Using Reflection to auto-fill in defaults in an object where possible

开发者 https://www.devze.com 2023-01-12 17:24 出处:网络
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.

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

  1. Use an enumeration of non static Field members
  2. 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));

0

精彩评论

暂无评论...
验证码 换一张
取 消