Dlaczego klasy Java nie dziedziczą adnotacji z zaimplementowanych interfejsów?

108

Używałem AOP Guice'a do przechwytywania niektórych wywołań metod. Moja klasa implementuje interfejs i chciałbym dodać adnotacje do metod interfejsu, aby Guice mógł wybrać odpowiednie metody. Nawet jeśli typ adnotacji jest adnotowany przy użyciu klasy implementującej Inherited adnotation, nie dziedziczy adnotacji, jak określono w dokumencie java Inherited:

Należy również zauważyć, że ta meta-adnotacja powoduje, że adnotacje są dziedziczone tylko z nadklas; adnotacje na zaimplementowanych interfejsach nie mają żadnego wpływu.

Co mogłoby być tego przyczyną? Zapoznanie się ze wszystkimi interfejsami, które klasa obiektu implementuje w środowisku wykonawczym, nie jest trudną rzeczą do zrobienia, więc musi być dobry powód takiej decyzji.

Boris Pavlović
źródło

Odpowiedzi:

130

Powiedziałbym, że powodem jest to, że w przeciwnym razie wystąpiłby problem wielokrotnego dziedziczenia.

Przykład:

@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{}

Jeśli to zrobię:

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

jaki będzie wynik? „baz”, „phleem” czy „flopp”?


Z tego powodu adnotacje na interfejsach rzadko są przydatne.

Sean Patrick Floyd
źródło
9
adnotacje na interfejsach są przydatne tylko wtedy, gdy masz framework, który je obsługuje. BTW w tym przykładzie getAnnotation () zwraca NULL;)
Peter Lawrey
6
No nie wiem ludzie. W tym przypadku (gdyby nie było literówki), spodziewałbym się The field value is ambiguous.błędu kompilatora podobnego do typu, podobnie jak w przypadku dwóch interfejsów deklarujących tę samą stałą z różnymi wartościami. Wiem, że to nie jest pole, ale wszystkie wartości adnotacji są rozwiązywane w czasie kompilacji, prawda? Funkcja, której tu brakuje, byłaby bardzo pomocna w wielu przypadkach. Swoją drogą, przepraszam za przywrócenie starego posta :).
Petr Janeček,
7
@Slanec spójrz na sposób, w jaki źródła Springa, aby zobaczyć, jak chłopaki Spring rozwiązali te problemy. Zobacz AnnotationUtils.findAnnotation (method, annotationType)
Sean Patrick Floyd
1
Rozważałem napisanie czegoś podobnego do tego. Przy jakimś prostym buforowaniu wydaje mi się, że jest to dobry sposób. Dzięki! W powyższym przykładzie znalazłby Fooadnotację ( MyClassnie ma jej, wtedy interfejsy są przeszukiwane i pobierane w kolejności, w jakiej są po implements) i dlatego wypisuje "baz". Chłodny.
Petr Janeček
2
@WChargin prawda, tylko 2 lata zajęło komuś wykrycie tej literówki :-)
Sean Patrick Floyd
35

Z Javadoc dla @Inherited:

Wskazuje, że typ adnotacji jest dziedziczony automatycznie. Jeśli dziedziczona meta-adnotacja jest obecna w deklaracji typu adnotacji, a użytkownik pyta o typ adnotacji w deklaracji klasy, a deklaracja klasy nie ma adnotacji dla tego typu, wówczas nadklasa klasy zostanie automatycznie zapytana o typ adnotacji. Ten proces będzie powtarzany do momentu znalezienia adnotacji dla tego typu lub osiągnięcia szczytu hierarchii klas (Object). Jeśli żadna z nadklasy nie ma adnotacji dla tego typu, zapytanie wskaże, że dana klasa nie ma takiej adnotacji. Zauważ, że ten typ meta-adnotacji nie działa, jeśli typ z adnotacją jest używany do opisywania czegokolwiek innego niż klasa. Należy również zauważyć, że ta meta-adnotacja powoduje, że adnotacje są dziedziczone tylko z nadklas;

Z drugiej strony, walidatory JSR 305 wykonują pewnego rodzaju wyszukiwanie dziedziczenia. Jeśli masz hierarchię klas:

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

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

Wtedy skuteczne walidacje na Student.getAge()@Nonnull @Min(5). @Nonnullnie ma @Inheritedmeta-adnotacji.

Eric Jablow
źródło
4
To powinna być wybrana odpowiedź
Andrzej Purtak
3
twój przykład zaprzecza twojej odpowiedzi, która mówi, że @Inheritednie ma to wpływu na nic innego niż klasa
Oleg Micheev
@Inherited działa tylko wtedy, gdy używasz adnotacji w Class
Carlos Parker