L'ho appena scoperto quando uno dei miei test di unità è fallito a causa dell'aggiornamento da Java 7 a Java 8. Il test dell'unità chiama un metodo che cerca di trovare un'annotazione su un metodo annotato su una classe figlia ma con un diverso tipo di ritorno.Perché isAnnotationPresent funziona in modo diverso tra Java 7 e Java 8?
In Java 7, isAnnotationPresent
sembra trovare solo annotazioni se sono state realmente dichiarate nel codice. In Java 8, isAnnotationPresent
sembra includere le annotazioni dichiarate nelle classi figlie.
Per illustrare ciò ho creato una semplice (??) classe di test IAPTest (per IsAnnotationPresentTest).
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class IAPTest {
@Retention(RetentionPolicy.RUNTIME)
public static @interface Anno {
}
public static interface I {
}
public static interface IE extends I {
}
public static class A {
protected I method() {
return null;
}
}
public static class B extends A {
@Anno
protected IE method() {
return null;
}
}
public static void main(String[] args) {
for (Method method : B.class.getDeclaredMethods()) {
if (method.getName().equals("method") && I.class.equals(method.getReturnType())) {
System.out.println(method.isAnnotationPresent(Anno.class));
}
}
}
}
Sul più recente Java 7 (1.7.0_79 al momento della scrittura), questo metodo stampa "false". Sull'ultimo Java 8 (1.8.0_66 al momento della scrittura), questo metodo stampa "true". Prevedo intuitivamente che stampi "false".
Perché è questo? Questo indica un bug in Java o un cambiamento previsto nel funzionamento di Java?
EDIT: Giusto per mostrare i comandi esatti che ho usato per replicare questo (in una directory con IAPTest.java identico al blocco di codice di cui sopra):
C:\test-isannotationpresent>del *.class
C:\test-isannotationpresent>set JAVA_HOME=C:\nma\Toolsets\AJB1\OracleJDK\jdk1.8.0_66
C:\test-isannotationpresent>set PATH=%PATH%;C:\nma\Toolsets\AJB1\OracleJDK\jdk1.8.0_66\bin
C:\test-isannotationpresent>java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
C:\test-isannotationpresent>javac IAPTest.java
C:\test-isannotationpresent>java IAPTest
true
C:\test-isannotationpresent>
Hmm, questo stampa 'false' per me: Eclipse Mars 4.5.1, JDK 1.8.0_51. – Tunaki
Perché pensi che le annotazioni "siano state dichiarate in classi di bambini"? Hai annotato il metodo in 'B' e stai cercando i * metodi dichiarati * di' B' e nient'altro. Non ci sono classi di bambini coinvolti. – Holger
@Holger quando cerco i metodi dichiarati di 'B', trovo due metodi. Un metodo rappresenta il metodo sulla classe figlio e uno rappresenta il metodo sulla classe genitore. Puoi dirlo dai tipi di ritorno. 'B.class.getDeclaredMethods(). Length == 2' su Java 7 e 8. Perché sto verificando il tipo restituito per garantire che il metodo della classe genitore sia quello a cui si fa riferimento (il tipo restituito è' I' anziché 'IE'), il metodo in' A' non ha l'annotazione, ma ha solo l'annotazione nella classe figlio 'B'. – Kidburla