Perché le classi Java non ereditano le annotazioni dalle interfacce implementate?


108

Ho usato l'AOP di Guice per intercettare alcune chiamate di metodo. La mia classe implementa un'interfaccia e vorrei annotare i metodi dell'interfaccia in modo che Guice possa selezionare i metodi giusti. Anche se il tipo di annotazione è annotato con l' annotazione ereditata, la classe di implementazione non eredita l'annotazione come dichiarato nel documento java di Inherited:

Nota anche che questa meta-annotazione fa sì che le annotazioni vengano ereditate solo dalle superclassi; le annotazioni sulle interfacce implementate non hanno effetto.

Quale potrebbe essere la ragione di ciò? Conoscere tutte le interfacce che la classe di un oggetto implementa in runtime non è una cosa difficile da fare, quindi ci deve essere una buona ragione dietro questa decisione.

Risposte:


130

Direi che il motivo è che altrimenti si verificherebbe un problema di ereditarietà multipla.

Esempio:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

Se lo faccio:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

quale sarà il risultato? "baz", "fleem" o "flopp"?


Per questo motivo, le annotazioni sulle interfacce sono raramente utili.


9
le annotazioni sulle interfacce sono utili solo se si dispone di un framework che le supporta. BTW in questo esempio getAnnotation () restituisce null;)
Peter Lawrey

6
Non lo so, gente. In questo caso (se l'errore di battitura non fosse presente), mi sarei aspettato un The field value is ambiguous.errore del compilatore simile a quello di due interfacce che dichiarano la stessa costante con valori diversi. So che questo non è un campo, ma i valori di annotazione vengono tutti risolti in fase di compilazione, no? La funzione che ci manca qui sarebbe molto utile in molti casi. A proposito, scusa per aver rianimato un vecchio post :)
Petr Janeček

7
@Slanec dà un'occhiata al modo in cui i sorgenti di Spring hanno risolto questi problemi. Vedi AnnotationUtils.findAnnotation (method, annotationType)
Sean Patrick Floyd,

1
Stavo pensando di scrivere qualcosa di simile a questo. Con una sorta di semplice memorizzazione nella cache, questo mi sembra un modo per andare. Grazie! Nell'esempio sopra, troverebbe l' Fooannotazione di ( MyClassnon ne ha una, quindi le interfacce vengono cercate e prese nell'ordine in cui sono dopo implements) e quindi stampa "baz". Freddo.
Petr Janeček

2
@WChargin vero, ci sono voluti solo 2 anni per qualcuno per individuare quell'errore di battitura :-)
Sean Patrick Floyd,

35

Dal Javadoc per @Inherited:

Indica che un tipo di annotazione viene ereditato automaticamente. Se una meta-annotazione ereditata è presente su una dichiarazione del tipo di annotazione e l'utente interroga il tipo di annotazione su una dichiarazione di classe e la dichiarazione di classe non ha annotazioni per questo tipo, la superclasse della classe verrà automaticamente interrogata per il tipo di annotazione. Questo processo verrà ripetuto fino a quando non viene trovata un'annotazione per questo tipo o viene raggiunta la parte superiore della gerarchia di classi (Object). Se nessuna superclasse ha un'annotazione per questo tipo, la query indicherà che la classe in questione non ha tale annotazione. Notare che questo tipo di meta-annotazione non ha effetto se il tipo annotato viene utilizzato per annotare qualcosa di diverso da una classe. Nota anche che questa meta-annotazione fa sì che le annotazioni vengano ereditate solo dalle superclassi;

D'altra parte, i validatori JSR 305 eseguono una sorta di ricerca dell'ereditarietà. Se hai una gerarchia di classi:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

Quindi le convalide effettive su Student.getAge()sono @Nonnull @Min(5). @Nonnullnon ha @Inheritedmeta-annotazioni.


4
Questa dovrebbe essere la risposta selezionata
Andrzej Purtak

3
il tuo esempio contraddice la tua risposta, che dice che @Inheritednon ha alcun effetto su nient'altro che sulla classe
Oleg Mikheev

@Ereditato funziona solo quando si utilizza l'annotazione su Classe
Carlos Parker
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.