Warum ist es nicht möglich, Anmerkungen in Java zu erweitern?


226

Ich verstehe nicht, warum Java-Annotationen keine Vererbung enthalten, genau wie Java-Klassen. Ich denke, es wäre sehr nützlich.

Zum Beispiel: Ich möchte wissen, ob eine bestimmte Anmerkung ein Validator ist. Mit der Vererbung konnte ich reflexartig durch Superklassen navigieren, um zu wissen, ob diese Annotation a erweitert ValidatorAnnotation. Wie kann ich das sonst erreichen?

Kann mir jemand einen Grund für diese Designentscheidung geben?


2
Übrigens, alle Annotationen erstrecken sich java.lang.annotation.Annotation, dh jede Annotation ist instanceofes, obwohl diese Tatsache nicht explizit deklariert ist.
Tomáš Záluský

Antworten:


166

Über den Grund, warum es nicht so entworfen wurde, finden Sie die Antwort in den JSR 175 Design FAQ, wo es heißt:

Warum unterstützen Sie die Untertypisierung von Anmerkungen nicht (wobei ein Anmerkungstyp einen anderen erweitert)?

Dies verkompliziert das Annotationstypsystem und erschwert das Schreiben von „spezifischen Tools“ erheblich.

"Spezifische Tools" - Programme, die bekannte Annotationstypen beliebiger externer Programme abfragen. Stub-Generatoren fallen beispielsweise in diese Kategorie. Diese Programme lesen mit Anmerkungen versehene Klassen, ohne sie in die virtuelle Maschine zu laden, laden jedoch Anmerkungsschnittstellen.

Also, ja, ich denke, der Grund ist, dass es nur KISS ist. Wie auch immer, es scheint, dass dieses Problem (zusammen mit vielen anderen) als Teil von JSR 308 untersucht wird , und Sie können sogar einen alternativen Compiler mit dieser Funktionalität finden, die bereits von Mathias Ricken entwickelt wurde .


67
Nun, vielleicht bin ich dumm, aber ich finde es schade, dass Annotationen nicht erweitert werden können, nur um "es einfach zu halten". Zumindest dachten Java-Designer nicht dasselbe über Klassenvererbung: P
sinuhepop

2
Java 8 M7 scheint keine Annotationen für Unterklassen zu unterstützen. Was für eine Schande.
Ceki

2
Bei @assylias JEP 104 geht es nicht darum, Anmerkungen in Unterklassen zu unterteilen. JEP 104 wurde in Java 8 implementiert, es ist jedoch immer noch nicht möglich, Annotationen in Unterklassen zu unterteilen (eine Annotation soll eine andere Annotation erweitern).
Jesper

71

Erweiterbare Anmerkungen würden die Belastung durch die Angabe und Wartung eines anderen Typsystems effektiv erhöhen. Und dies wäre ein ziemlich einzigartiges Typsystem, so dass Sie nicht einfach ein OO-Typ-Paradigma anwenden könnten.

Denken Sie über alle Probleme nach, wenn Sie Polymorphismus und Vererbung in eine Annotation einführen (z. B. was passiert, wenn die Sub-Annotation Meta-Annotation-Spezifikationen wie die Aufbewahrung ändert?).

Und all diese zusätzliche Komplexität für welchen Anwendungsfall?

Sie möchten wissen, ob eine bestimmte Anmerkung zu einer Kategorie gehört?

Versuche dies:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

Wie Sie sehen, können Sie mithilfe der bereitgestellten Funktionen problemlos Anmerkungen ohne übermäßige Schmerzen gruppieren und kategorisieren.

Also, KISS ist der Grund für ein Meta-Typ - Typ - System auf die Java - Sprache einzuführen.

[ps edit]

Ich habe den String nur zur Demonstration und im Hinblick auf eine offene Meta-Annotation verwendet. Für Ihr eigenes Projekt können Sie natürlich eine Aufzählung von Kategorietypen verwenden und für eine bestimmte Anmerkung mehrere Kategorien ("Mehrfachvererbung") angeben. Beachten Sie, dass die Werte völlig falsch sind und nur zu Demonstrationszwecken dienen:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    AnnotationCategory[] category();
}
public enum AnnotationCategory {
    GENERAL,
    SEMANTICS,
    VALIDATION,
    ETC
}

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {

}


Funktioniert nicht funktioniert wird falsch gedruckt:@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) @interface C {}; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @C public @interface F {} class a{ @F public void S() {} } @Test public void blahTest() throws NoSuchMethodException { Method m = a.class.getMethod("S"); System.out.println(m.isAnnotationPresent(C.class)); }
user1615664

Wir kommentieren eine Anmerkung. a # S hat die Annotation F. F selbst wird von C annotiert. Versuchen Sie das.
Alphazero

Ja, das ist richtig. Aber gibt es eine Möglichkeit, dies sauberer zu tun, als den Annotation-Proxy zu lesen?
user1615664

12

In gewisser Weise haben Sie es bereits mit Anmerkungen - Meta-Anmerkungen. Wenn Sie eine Annotation mit Metainformationen versehen, entspricht dies in vielerlei Hinsicht der Erweiterung einer zusätzlichen Schnittstelle. Anmerkungen sind Schnittstellen, sodass Polymorphismus nicht wirklich ins Spiel kommt. Da sie statischer Natur sind, kann es kein dynamisches Laufzeit-Dispatching geben.

In Ihrem Validator-Beispiel können Sie einfach in der Annotation den kommentierten Typ abrufen und prüfen, ob er eine Validator-Meta-Annotation enthält.

Der einzige Anwendungsfall, den ich sehen konnte, dass Vererbung helfen würde, ist, wenn Sie in der Lage sein möchten, die Annotation nach Supertyp zu erhalten, aber dies würde eine ganze Reihe von Komplexität hinzufügen, da eine bestimmte Methode oder ein bestimmter Typ möglicherweise zwei solche Annotationen enthält. Dies bedeutet, dass ein Array anstelle nur eines einzelnen Objekts zurückgegeben werden muss.

Daher denke ich, dass die ultimative Antwort darin besteht, dass die Anwendungsfälle esoterisch sind und mehr Standardanwendungsfälle komplizieren, sodass es sich nicht lohnt.


5

Die Entwickler der Java-Annotationsunterstützung haben eine Reihe von "Vereinfachungen" zum Nachteil der Java-Community vorgenommen.

  1. Keine Annotationen-Subtypen machen viele komplexe Annotationen unnötig hässlich. Man kann nicht einfach ein Attribut in einer Annotation haben, das eines von drei Dingen enthalten kann. Man muss drei separate Attribute haben, was Entwickler verwirrt und eine Laufzeitvalidierung erfordert, um sicherzustellen, dass nur eines der drei verwendet wird.

  2. Nur eine Anmerkung eines bestimmten Typs pro Site. Dies hat zu einem völlig unnötigen Anmerkungsmuster für Sammlungen geführt. @Validation und @Validations, @Image und @Images usw.

Das zweite Problem wird in Java 8 behoben, aber es ist zu spät. Viele Frameworks wurden basierend auf dem geschrieben, was in Java 5 möglich war, und jetzt sind diese API-Warzen für eine lange Zeit hier.


1
Darüber hinaus ist es nicht möglich, Eigenschaften mit rekursiv verschachtelten Attributen zu definieren, die vom XML-Schema unterstützt werden. Dies macht Annotationen weniger leistungsfähig als XML
user2833557

3

Ich könnte drei Jahre zu spät auf diese Frage antworten, aber ich fand es interessant, weil ich mich an derselben Stelle befand. Hier ist meine Meinung dazu. Sie können Anmerkungen als Aufzählungen anzeigen. Sie bieten eine einseitige Art von Informationen - verwenden Sie sie oder verlieren Sie sie.

Ich hatte eine Situation, in der ich GET, POST, PUT und DELETE in einer Web-App simulieren wollte. Ich wollte unbedingt eine "super" Annotation mit dem Namen "HTTP_METHOD" haben. Später wurde mir klar, dass es keine Rolle spielte. Nun, ich musste mich damit abfinden, ein verstecktes Feld im HTML-Formular zu verwenden, um DELETE und PUT zu identifizieren (da POST und GET sowieso verfügbar waren).

Auf der Serverseite habe ich nach einem versteckten Anforderungsparameter mit dem Namen "_method" gesucht. Wenn der Wert PUT oder DELETE war, wurde die zugehörige HTTP-Anforderungsmethode überschrieben. Trotzdem war es egal, ob ich eine Anmerkung erweitern musste oder nicht, um die Arbeit zu erledigen. Alle Anmerkungen sahen gleich aus, wurden jedoch auf der Serverseite unterschiedlich behandelt.

Lassen Sie in Ihrem Fall den Juckreiz fallen, um Anmerkungen zu erweitern. Behandle sie als "Marker". Sie "repräsentieren" einige Informationen und "manipulieren" nicht unbedingt einige Informationen.


2

Eine Sache, an die ich denken könnte, ist die Möglichkeit, mehrere Anmerkungen zu haben. Sie können also an derselben Stelle einen Validator und eine spezifischere Anmerkung hinzufügen. Aber ich könnte mich irren :)


2

Ich habe nie darüber nachgedacht, aber ... scheint, dass Sie Recht haben, es gibt kein Problem mit der Vererbungsfunktion für Anmerkungen (zumindest sehe ich das Problem damit nicht).

Über Ihr Beispiel mit der Annotation "Validator" - Sie können dann den Ansatz der "Meta-Annotation" nutzen . Das heißt, Sie wenden eine bestimmte Meta-Annotation auf die gesamte Annotation-Oberfläche an.


Ich könnte drei Jahre zu spät auf diese Frage antworten, aber ich fand es interessant, weil ich mich an derselben Stelle befand.
Mainas

1

das gleiche Problem habe ich. Nein, das kannst du nicht. Ich habe mich selbst "diszipliniert", um Eigenschaften in Anmerkungen zu schreiben, um einige Standards zu respektieren. Wenn Sie also Anmerkungen erhalten, können Sie außerhalb der Eigenschaften "schnüffeln", welche Art von Anmerkung es ist, nach Eigenschaften, die es hat.

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.