简体   繁体   English

在可能的情况下使用反射自动填充对象的默认值

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

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. 这是我一直在整理的一些代码,它们试图懒惰地填充对象中的字段,主要用于JUnit中的对象工厂,但是它可能是一个非常有用的方法。

    private void lazyObjectFill(Object 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(""); 运行m.invoke(“”)时会发生异常。 on a string setter. 在字符串设置器上。


Updated source code for the benefit of the googlers. 更新了源代码,以使Google员工受益。

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. 您几乎在那里,但是方法是静态的,它们需要一个可以在其上调用它们的对象。

ie

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 . 可以在方法javadoc中找到详细信息。

BTW: Static methods are invoked like this: 顺便说一句:静态方法是这样调用的:

method.invoke(null, params);

You know that invoke method of Method takes two arguments ? 您知道Method的invoke方法带有两个参数吗? As a consequence, I guess you wrote 结果,我想你写了

m.invoke(profil, "")

Besides, I would personnally not have separated String from other objects. 此外,我个人不会将String与其他对象分开。

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. 使用BeanInfo访问bean属性。

The first parameter of the Method.invoke() is the object which will invoke the method. Method.invoke()的第一个参数是将调用该方法的对象。

For example in your case m.invoke(profil, ""); 例如,在您的情况下, m.invoke(profil, ""); or m.invoke(profil, Defaults.defaultValue(clazz)); m.invoke(profil, Defaults.defaultValue(clazz));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM