При настройке 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 каким-то образом некорректно?