2009-10-12 7 views
75

Ich versuche, zwei oder mehr Anmerkungen des gleichen Typs auf ein einzelnes Element, in diesem Fall eine Methode zu schlagen. Hier ist der ungefähre Code, ich arbeite mit:Mehrere Annotationen des gleichen Typs auf einem Element?

public class Dupe { 
    public @interface Foo { 
     String bar(); 
    } 

    @Foo(bar="one") 
    @Foo(bar="two") 
    public void haha() {} 
} 

Beim Kompilieren der oben Javac beschwert sich über eine doppelte Anmerkung:

 
[email protected]:~/work/daybreak$ javac Dupe.java 
Dupe.java:5: duplicate annotation 

Ist es einfach nicht möglich, Anmerkungen wie diese zu wiederholen? Sind die beiden Instanzen von @Foo nicht pedantisch unterschiedlich, weil ihre Inhalte unterschiedlich sind?

Wenn das obige nicht möglich ist, was sind einige mögliche Problemumgehungen?

UPDATE: Ich wurde gebeten, meinen Anwendungsfall zu beschreiben. Hier geht.

Ich bin ein Syntax Sugarish-Mechanismus zum "Mappen" POJOs zu Dokumenten speichert wie MongoDB. Ich möchte zulassen, dass Indizes als Anmerkungen auf den Gettern oder Sätzen angegeben werden. Hier ist ein konstruiertes Beispiel:

public class Employee { 
    private List<Project> projects; 

    @Index(expr = "project.client_id") 
    @Index(expr = "project.start_date") 
    public List<Project> getProjects() { return projects; } 
} 

Offensichtlich möchte ich schnell in der Lage sein, um Fälle von Mitarbeiter durch verschiedene Eigenschaften des Projekts zu finden. Ich kann @Index entweder zweimal mit verschiedenen expr() - Werten angeben oder den in der akzeptierten Antwort angegebenen Ansatz wählen. Obwohl Hibernate dies tut und nicht als Hack betrachtet wird, halte ich es immer noch für sinnvoll, zumindest mehrere Annotationen desselben Typs auf einem einzelnen Element zuzulassen.

+1

Es ist ein Bemühen Sie sich, diese doppelte Regel zu lockern, um Ihr Programm in Java 7 zu erlauben. Können Sie bitte Ihren Anwendungsfall beschreiben? – notnoop

+0

Ich habe meine Frage mit einer Beschreibung bearbeitet, warum ich das machen möchte. Vielen Dank. –

+0

In CDI könnte es praktisch sein, eine Bean für mehrere Qualifier bereitzustellen. Zum Beispiel habe ich gerade versucht, eine Bohne an zwei Stellen wiederzuverwenden, indem ich sie "@Producedes @PackageName (" test1 ") @PackageName (" test2 ")" –

Antwort

127

Zwei oder mehr Anmerkungen desselben Typs sind nicht zulässig. Sie könnten jedoch so etwas tun:

public @interface Foos { 
    Foo[] value(); 
} 

@Foos({@Foo(bar="one"), @Foo(bar="two")}) 
public void haha() {} 

Sie benötigen dedizierte Behandlung von Foos Annotation in Code jedoch.

btw, ich habe das vor 2 Stunden nur verwendet um das gleiche Problem zu arbeiten :)

+2

Kannst du das auch in Groovy machen? – Excel20

+5

@ Excel20 Ja. Sie müssten jedoch eckige Klammern verwenden, z. '@Foos ([@ Foo (bar =" eins "), @Foo (bar =" zwei ")])'. Siehe http://groovy.codehaus.org/Annotations+mit+Groovy – sfussenegger

+0

Ein bisschen spät am Tag, aber darauf achten, auf den Rat zu verweisen, der die Liste von Foo in Foos verarbeiten kann? Im Moment versuche ich, das Ergebnis einer Methode zu verarbeiten, aber obwohl das Foos abgefangen wird, wird der Foo-Rat nie eingegeben. –

12

Wie sfussenegger sagt, ist dies nicht möglich.

Die übliche Lösung ist Erstellen Sie eine "multiple" Annotation, die ein Array der vorherigen Annotation behandelt. Es wird normalerweise mit dem Suffix "s" gleich benannt.

Übrigens wird dies in großen öffentlichen Projekten (Hibernate zum Beispiel) sehr häufig verwendet, so dass es nicht als Hack, sondern als richtige Lösung für diesen Bedarf betrachtet werden sollte.


Je nach Bedarf könnte es besser sein, lassen Sie Ihre früheren Anmerkung mehrere Werte zu handhaben.

Beispiel:

public @interface Foo { 
     String[] bars(); 
    } 
+0

Ich wusste, dass dies unheimlich vertraut war. Danke, dass du mein Gedächtnis aufgefrischt hast. –

+0

Es ist jetzt mit Java 8 möglich. – AnixPasBesoin

3

Wenn Sie nur 1 Parameter "bar" haben Sie es als "Wert" nennen kann. In diesem Fall müssen Sie nicht die Parameternamen überhaupt schreiben, wenn Sie es wie folgt verwendet werden:

@Foos({@Foo("one"), @Foo("two")}) 
public void haha() {} 

etwas kürzer und übersichtliche, imho ..

+0

Korrekter Punkt, aber wie versucht man, die Frage von OP zu beantworten? – Mordechai

+0

@MouseEvent du hast Recht, ich denke es war eher eine Verbesserung der Topantwort von sfussenegger und gehört somit eher in die Kommentare da oben. Aber die Antwort ist sowieso veraltet wegen der wiederholbaren Anmerkungen ... – mihahh

3

die anderen Antworten in die einfachste Form der Kombination von ... eine Anmerkung mit einer einfachen Liste von Werten ...

11

http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html

von Java8 starten können Sie beschreiben wiederholbar Anmerkungen:

@Repeatable(FooValues.class) 
public @interface Foo { 
    String bar(); 
} 

public @interface FooValues { 
    Foo[] value(); 
} 

Hinweis, value ist ein Pflichtfeld für die Werteliste.

Jetzt können Sie Anmerkungen verwenden sie zu wiederholen, anstatt die Anordnung der Füllung:

@Foo(bar="one") 
@Foo(bar="two") 
public void haha() {} 
9

Neben den anderen Möglichkeiten erwähnt, gibt es noch eine weniger ausführliche Art und Weise in Java8:

@Target(ElementType.TYPE) 
@Repeatable(FooContainer.class) 
@Retention(RetentionPolicy.RUNTIME) 
@interface Foo { 
    String value(); 

} 

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
@interface FooContainer { 
     Foo[] value(); 
     } 

@Foo("1") @Foo("2") @Foo("3") 
class Example{ 

} 

Beispiel durch Verzug, FooContainer als Annotation

Arrays.stream(Example.class.getDeclaredAnnotations()).forEach(System.out::println); 
    System.out.println(Example.class.getAnnotation(FooContainer.class)); 

Sowohl die oben Druck:

@ com.FooContainer (Wert = [@ com.Foo (Wert = 1), @ com.Foo (Wert = 2), @ com.Foo (Wert = 3)])

@ com.FooContainer (Wert = [@ com.Foo (Wert = 1), @ com.Foo (Wert = 2), @ com.Foo (Wert = 3)])

+0

Es ist erwähnenswert, dass Methode/Feldname in FooContainer muss streng "value()" genannt werden. Ansonsten wird Foo nicht kompilieren. – Tomasz

+0

... auch der Annotationstyp (FooContainer) kann nicht auf mehr Typen als den wiederholbaren Annotationstyp (Foo) angewendet werden. – Tomasz

Verwandte Themen