0

这是我一直在玩弄的一些代码,用于尝试懒惰地填充对象中的字段,主要用于 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));
                }
            }

        }
    }
}

在对象上运行此代码时,我们得到以下异常。

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)

运行时出现异常 m.invoke(""); 在字符串设置器上。


为谷歌员工的利益更新了源代码。

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

        }
    }
}
4

3 回答 3

4

你快到了,但方法是静态的,它们需要一个对象来调用它们。

IE

m.invoke(profil, "");

m.invoke(profil, Defaults.defaultValue(clazz));

您(在不知不觉中)试图在没有参数的字符串对象上执行该方法。而且由于字符串类没有那个方法,它必须失败。详细信息可以在Method javadoc中找到。

顺便说一句:静态方法是这样调用的:

method.invoke(null, params);
于 2010-08-24T13:57:57.730 回答
2

你知道Method 的调用方法需要两个参数吗?结果,我猜你写了

m.invoke(profil, "")

此外,我个人不会将 String 与其他对象分开。

最后,为了正确识别对象字段,我更喜欢混合方法

  1. 使用非静态字段成员的枚举
  2. 使用BeanInfo访问 bean 属性。
于 2010-08-24T13:59:40.660 回答
1

的第一个参数Method.invoke()是将调用该方法的对象。

例如,在您的情况下m.invoke(profil, "");m.invoke(profil, Defaults.defaultValue(clazz));

于 2010-08-24T14:00:09.080 回答