Während ich Hudson für kontinuierliche Integrationstests (auf einem JeOS-Server) eingerichtet habe, bin ich auf ein merkwürdiges Verhalten gestoßen, auf das ich hoffe, dass die netten Leute von SO mir das erklären können.Ist die Java-Reflektion über vererbte Methoden in Windows und Linux anders?
Unsere Komponententests hängen stark von der Verwendung von Domänenobjekten mit vielen Eigenschaften ab, die festgelegt werden müssen (aufgrund von Nullbedingungen in der Datenbank). Um unsere Tests lesbar zu halten, haben wir eine Klasse InstantiationUtils erstellt, die ein Objekt instanziiert und eine Reihe von Eigenschaften durch Reflexion gesetzt:
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;
}
}
Die Person, die leider dieser Code nicht mehr funktioniert für uns geschrieben hat, aber als Soweit ich sehen kann, ist nichts falsch daran. Das gilt auch für Windows - wir verwenden InstantiationUtils während unserer Komponententests ohne Probleme.
Linux ist jedoch anders. Es stellt sich heraus, dass die Methode newInstance() in Linux nur für direkte (d. H. Nicht geerbte) Elemente der Klasse, die wir instanziieren möchten, funktioniert.
InstantiationUtils.newInstance (Bar.class, "bar", "12345"); wird funktionieren, während InstantiationUtils.newInstance (Bar.class, "foo", "98765");
xxx.xxx.xxx.ReflectionUtils $ Reflection: java.lang.NoSuchMethodException: Eigenschaft 'foo' hat keine Setter-Methode
Unter Windows wird sowohl mit folgenden Ausnahme wird auf Linux scheitern Aufrufe funktionieren (ich weiß, dass die newInstance-Signatur nicht übereinstimmt; wir haben mehrere überladene newInstance() -Methoden, die die Parameter in KeyValuePairs konvertieren).
Ich hatte eine schwere Zeit zu akzeptieren, dass vererbte öffentliche Methoden anders behandelt werden, also habe ich dies auf alle möglichen Arten getestet. Und es endet immer mit der Schlussfolgerung, dass wir unter Linux, zumindest mit der obigen Verwendung von Reflection, nicht auf öffentliche vererbte Methoden zugreifen können.
Unter Windows verwende ich Suns JRE 1.6.0.11, in Linux ist es auch Sun, aber Version 1.6.0.7.
Kann jemand bestätigen, ob das richtig ist? Oder ist die Reflection-Verwendung fehlerhaft?
Verwenden Sie die gleiche Version der JRE auf beiden Betriebssystemen? Das klingt nach einer viel wahrscheinlichen Ursache für Diskrepanzen als das Betriebssystem. Wenn Sie Ihren Code zu einem einzigen vollständigen Beispiel zusammenfassen könnten, wäre es einfacher zu überprüfen und zu erkunden. –
"Linux ist jedoch anders. Es stellt sich heraus, dass die Methode newInstance() in Linux nur für direkte (d. H. Nicht vererbte) Mitglieder der Klasse funktioniert, die wir instanziieren möchten." 23 Tage früher. – phihag