A co natchnęło mnie do powrotu na bloga - otóż znalazłem buga w Javie :), a dokładniej w implementacji introspekcji (java.beans.*). Na problem natknąłem się rozwijając aplikację webową, co tylko utrudniło wyodrębnienie go, ale w końcu się udało ! Na początek trochę kodu:
public interface ITest<T> {
public T getDelta();
}
public class Foo implements ITest<String> {
private List<String> alfa;
private String beta;
private String gamma;
public List<String> getAlfa() {
return alfa;
}
public void setAlfa(final List<String> alfa) {
this.alfa = alfa;
}
public String getBeta() {
return beta;
}
public void setBeta(final String beta) {
this.beta = beta;
}
public String getDelta() {
return gamma;
}
public void setDelta(final String gamma) {
this.gamma = gamma;
}
}
public class Bar implements ITest<String> {
private List<String> alfa;
private String beta;
private String gamma;
public List<String> getAlfa() {
return alfa;
}
public void setAlfa(final List<String> alfa) {
this.alfa = alfa;
}
public String getGamma() {
return gamma;
}
public void setGamma(final String gamma) {
this.gamma = gamma;
}
public String getBeta() {
return beta;
}
public void setBeta(final String beta) {
this.beta = beta;
}
public String getDelta() {
return gamma;
}
public void setDelta(String gamma) {
this.gamma = gamma;
}
}
I najważniejsza część - kod testujący. Pobiera deskryptory pól dla każdej z klas, a następnie wypisuje metody zapisu dla poszczególnych deskryptorów. Mowiąc prościej kod wyświetla settery zgodne ze specyfikacją JavaBeans (jeśli nie ma - wypisze 'null'):
Dla ułatwienia będę podawał wartości tylko dla property: "delta".
Po wywołaniu kodu powyżej otrzymamy wynik:
"delta null" (dla Foo)
"delta null" (dla Bar)
Po zamianie wywołań dostaniemy:
"delta public void pl.test.Bar.setDelta(java.lang.String)"
"delta null"
Po zakomentowaniu części "Dla Foo" wynik będzie:
"delta public void pl.test.Bar.setDelta(java.lang.String)"
Natomiast po zakomentowaniu części "Dla Bar" na konsoli pojawi się znowu:
"delta null"
Szczerze mówiąc powyższe wyniki są dla mnie kompletnie niedeterministyczne ;D. Mogę jedynie domniemywać, że ma to jakiś związek z typami generycznymi i cache'owaniem przy introspekcji. Strzelałbym nawet, że w tym przypadku łączy się więcej niż jeden bug, stąd dość "ciekawe" rezultaty". Biorąc nawet pod uwagę, że są znane problemy na styku JavaBeans i generyków1 powyższe wyniki wydają się definitywnie zbyt "pseudo-losowe" ;).
Wszystko będzie ok jeśli:
- zarówno 'getter' i 'setter' jest generyczny i dziedziczony,
- i co ciekawe ... 'setter' jest generyczny i dziedziczony
1. Warto popatrzeć na następujące zgłoszenia:
http://bugs.sun.com/view_bug.do?bug_id=6422403
http://bugs.sun.com/view_bug.do?bug_id=6473468
http://bugs.sun.com/view_bug.do?bug_id=5098163
No comments:
Post a Comment