Warum erben Java-Klassen keine Anmerkungen von implementierten Schnittstellen?


108

Ich habe Guices AOP verwendet, um einige Methodenaufrufe abzufangen. Meine Klasse implementiert eine Schnittstelle und ich möchte die Schnittstellenmethoden mit Anmerkungen versehen, damit Guice die richtigen Methoden auswählen kann. Selbst wenn der Annotationstyp mit der Implementierungsklasse für geerbte Annotationen annotiert wird, erbt die Annotation nicht die Annotation, wie in Inheriteds Java-Dokument angegeben:

Beachten Sie auch, dass diese Meta-Annotation nur dazu führt, dass Annotationen von Superklassen geerbt werden. Anmerkungen zu implementierten Schnittstellen haben keine Auswirkung.

Was könnte der Grund dafür sein? Es ist nicht so schwer, alle Schnittstellen kennenzulernen, die die Klasse eines Objekts zur Laufzeit implementiert. Es muss also einen guten Grund für diese Entscheidung geben.

Antworten:


130

Ich würde sagen, der Grund ist, dass sonst ein Mehrfachvererbungsproblem auftreten würde.

Beispiel:

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

Wenn ich das mache:

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

Was wird das Ergebnis sein? 'baz', 'phleem' oder 'flopp'?


Aus diesem Grund sind Anmerkungen zu Schnittstellen selten nützlich.


9
Anmerkungen zu Schnittstellen sind nur dann nützlich, wenn Sie über ein Framework verfügen, das sie unterstützt. Übrigens in diesem Beispiel getAnnotation () gibt null zurück;)
Peter Lawrey

6
Ich weiß nicht, Leute. In diesem Fall (wenn der Tippfehler nicht vorhanden wäre) würde ich einen The field value is ambiguous.ähnlichen Compilerfehler erwarten, genau wie bei zwei Schnittstellen, die dieselbe Konstante mit unterschiedlichen Werten deklarieren. Ich weiß, dass dies kein Feld ist, aber Annotationswerte werden alle beim Kompilieren aufgelöst, nicht wahr? Die Funktion, die wir hier vermissen, wäre in vielen Fällen sehr hilfreich. Tut mir leid, dass ich einen alten Beitrag wiederbelebt habe :).
Petr Janeček

7
@Slanec werfen Sie einen Blick auf die Art und Weise, wie die Quellen von Spring diese Probleme umgehen. Siehe AnnotationUtils.findAnnotation (Methode, AnnotationType)
Sean Patrick Floyd

1
Ich dachte darüber nach, etwas Ähnliches zu schreiben. Mit einer Art einfachem Caching scheint dies ein Weg für mich zu sein. Vielen Dank! Im obigen Beispiel würde es die FooAnnotation des 's finden ( MyClasshat keine, dann werden die Schnittstellen durchsucht und in der Reihenfolge genommen, in der sie sich befinden implements) und daher "baz" drucken. Cool.
Petr Janeček

2
@WChargin stimmt, es hat nur 2 Jahre gedauert, bis jemand diesen Tippfehler entdeckt hat :-)
Sean Patrick Floyd

35

Aus dem Javadoc für @Inherited:

Gibt an, dass ein Anmerkungstyp automatisch vererbt wird. Wenn eine geerbte Meta-Annotation in einer Annotationstypdeklaration vorhanden ist und der Benutzer den Annotationstyp in einer Klassendeklaration abfragt und die Klassendeklaration keine Annotation für diesen Typ enthält, wird die Oberklasse der Klasse automatisch nach dem Annotationstyp abgefragt. Dieser Vorgang wird wiederholt, bis eine Anmerkung für diesen Typ gefunden wird oder die Spitze der Klassenhierarchie (Objekt) erreicht ist. Wenn keine Oberklasse eine Annotation für diesen Typ hat, zeigt die Abfrage an, dass die betreffende Klasse keine solche Annotation hat. Beachten Sie, dass dieser Meta-Annotationstyp keine Auswirkung hat, wenn der annotierte Typ zum Annotieren von etwas anderem als einer Klasse verwendet wird. Beachten Sie auch, dass diese Meta-Annotation nur dazu führt, dass Annotationen von Superklassen geerbt werden.

Auf der anderen Seite führen JSR 305-Validatoren eine Art Vererbungssuche durch. Wenn Sie eine Klassenhierarchie haben:

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

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

Dann werden die effektiven Validierungen Student.getAge()sind @Nonnull @Min(5). @Nonnullhat keine @InheritedMeta-Annotation.


4
Dies sollte die ausgewählte Antwort sein
Andrzej Purtak

3
Ihr Beispiel widerspricht Ihrer Antwort, die besagt, dass dies @Inheritedkeine Auswirkung auf etwas anderes als die Klasse hat
Oleg Mikheev

@ Vererbt funktioniert nur, wenn Sie die Annotation auf Class
Carlos Parker
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.