Использование Reflection для автоматического заполнения значений по умолчанию в объекте, где это возможно - PullRequest
0 голосов
/ 24 августа 2010

Вот код, с которым я вертелся, чтобы попытаться лениво заполнить поля в объекте, в основном для объектных фабрик в 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 ("");на строковом установщике.


Обновлен исходный код для удобства пользователей 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));
                }
            }

        }
    }
}

Ответы [ 3 ]

4 голосов
/ 24 августа 2010

Вы почти у цели, но методы статичны, и им нужен объект для их вызова.

т.е.

m.invoke(profil, "");

и

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

Выпытались (неосознанно) выполнить метод на строковом объекте без параметров.И так как у строкового класса нет этого метода, он должен был потерпеть неудачу.Подробности можно найти в Методе javadoc .

Кстати: статические методы вызываются так:

method.invoke(null, params);
2 голосов
/ 24 августа 2010

Вы знаете, что invoke метод Method принимает два аргумента? Как следствие, я думаю, вы написали

m.invoke(profil, "")

Кроме того, я бы лично не отделял String от других объектов.

И, наконец, для правильной идентификации полей объекта я бы предпочел смешанный подход

  1. Использовать перечисление нестатических членов поля
  2. Используйте BeanInfo для доступа к свойствам бина.
1 голос
/ 24 августа 2010

Первый параметр Method.invoke() - это объект, который будет вызывать метод.

Например, в вашем случае m.invoke(profil, ""); или m.invoke(profil, Defaults.defaultValue(clazz));

...