Отличается ли Java-отражение в унаследованных методах в Windows и Linux? - PullRequest
2 голосов
/ 09 марта 2009

При настройке Hudson для непрерывного тестирования интеграции (на сервере JeOS) я столкнулся с некоторым странным поведением, которое, я надеюсь, хорошие люди из SO могут мне объяснить.

Наши модульные тесты сильно зависят от использования доменных объектов с большим количеством свойств, которые должны быть установлены (из-за нулевых ограничений в базе данных). Чтобы сделать наши тесты читабельными, мы создали класс InstantiationUtils, который может создавать экземпляр объекта и задавать ряд свойств с помощью отражения:

public static <T> T newInstance(final Class<T> type, final KeyValuePair<?>... propertyValues) {

    return ReflectionUtils.reflectionOperation(new ReflectionOperation<T>() {

        @Override
        public T perform() throws Exception {

            T object = type.newInstance();
            for (KeyValuePair<?> propertyValue : propertyValues) {

                String propertyName = propertyValue.getKey();
                Object value = propertyValue.getValue();
                String setterName = "set" + StringUtils.capitalize(propertyName);
                ReflectionUtils.invoke(object, setterName, value);
            }
            return object;
        }
    });
}

public static void invoke(final Object target, final String methodName, final Object... params) {

    List<Class<?>> parameterTypes = ListUtils.map(asList(params), "class");
    Class<?> targetClass = target.getClass();
    Method method = MethodUtils.getMatchingAccessibleMethod(targetClass, methodName,
        parameterTypes.toArray(new Class<?>[] {}));
    invoke(target, method, params);
}

public class Foo {
    private String foo;

    public void setFoo(final String foo) {
        this.foo = foo;
    }
}

public class Bar extends Foo {
    private String bar;

    public void setBar(final String bar) {
       this.bar = bar;
    }
}

Человек, который написал этот код, к сожалению, больше не работает для нас, но, насколько я понимаю, в этом нет ничего плохого. Что также верно для Windows - мы используем InstantiationUtils во время наших модульных тестов без проблем.

Linux, однако, отличается. Оказывается, что в Linux метод newInstance () работает только для прямых (то есть не унаследованных) членов класса, который мы хотим создать.

InstantiationUtils.newInstance (Bar.class, "bar", "12345"); будет работать, пока InstantiationUtils.newInstance (Bar.class, "foo", "98765"); произойдет сбой в Linux, со следующим исключением:

xxx.xxx.xxx.ReflectionUtils $ ReflectionException: java.lang.NoSuchMethodException: свойство 'foo' не имеет метода установки

В Windows оба вызова будут работать (я знаю, что подпись newInstance не совпадает; у нас есть несколько перегруженных методов newInstance (), которые преобразуют параметры в KeyValuePairs).

Мне было трудно признать, что унаследованные публичные методы обрабатываются по-разному, поэтому я проверил это всеми возможными способами. И это всегда заканчивается выводом о том, что в Linux, по крайней мере с использованием вышеупомянутого Reflection, мы не можем получить доступ к публичным унаследованным методам.

В Windows я использую Sun JRE 1.6.0.11, в Linux это также Sun, но версия 1.6.0.7.

Может ли кто-нибудь подтвердить, правильно ли это? Или использование Reflection каким-то образом некорректно?

Ответы [ 7 ]

3 голосов
/ 09 марта 2009

Вы используете MethodUtils, и у него есть некоторые ограничения :

Известные ограничения

Доступ к открытым методам в суперклассе Access по умолчанию

Существует проблема при вызове открытых методов, содержащихся в суперклассе доступа по умолчанию. Reflection находит эти методы в порядке и правильно назначает их как public. Тем не менее, IllegalAccessException генерируется, если метод вызывается.

Еще одна вещь, которую нужно проверить - перегружен ли метод setFoo (), это также может вызвать проблему ...

2 голосов
/ 09 марта 2009

Может ли быть так, что настройки SecurityManager различны для разных сред выполнения Java?

Конечно, я сомневаюсь, что это проблема платформы - это почти наверняка связано с версией / настройкой JRE между двумя средами

Вам действительно нужно отправить исходный код на MethodUtils.getMatchingAccessibleMethod

1 голос
/ 09 марта 2009

Тайна частично раскрыта:

MethodUtils.getMatchingAccessibleMethod (), очевидно, работает по-разному в Linux и Windows.

Используя взамен MethodUtils.getAccessibleMethod (), он работает. Почему, я не знаю, но я предполагаю, что MethodUtils каким-то образом неверно истолковывает список параметров, когда выясняет, какую подпись должен иметь метод.

Я бы хотел потратить больше времени на изучение этого, но, как всегда, есть вещи, которые нужно сделать, и проекты, которые нужно реализовать, поэтому я просто должен признать, что getAccessibleMethod работает, и двигаться дальше: -)

Спасибо всем за вклад!

1 голос
/ 09 марта 2009

Несколько вещей, чтобы попробовать ...

В Linux попробуйте скомпилировать код без рефлексивного вызова getFoo () - если он не скомпилируется, то у отражения нет надежды на работу (ну, это зависит от того, как вы настроили CLASSAPTH во время выполнения ...)

Попробуйте добавить приведенный ниже код и запустить его как в Linux, так и в Windows.

final Properties properties;

properties = System.getProperties();

for(final Entry<Object, Object> entry : properties.entrySet())
{
    System.out.println(entry.getKey() + " " + entry.getValue());
}

Проверьте вывод, чтобы убедиться, что вы используете smae JDK / JRE. Также проверьте, правильно ли указан путь к классу, и вы действительно загружаете то, что, как вы думаете, загружаете.

0 голосов
/ 09 марта 2009

Вы проверили свой CLASSPATH? Подбираете ли вы разные версии класса, который хотите создать, в зависимости от того, на какой платформе вы находитесь? (например, старые кодовые базы, лежащие вокруг и т. д.?)

0 голосов
/ 09 марта 2009

У вас есть разные локали? StringUtils.capitalize(propertyName) может производить различную продукцию.

0 голосов
/ 09 марта 2009

Какую JVM вы используете в Linux, Sun, GCJ и т. Д.? Если вы используете что-то еще, кроме Sun JVM, вы можете попробовать установить его и посмотреть, будет ли это иметь значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...