2009-10-12 14 views
75

Sto tentando di eseguire lo slap di due o più annotazioni dello stesso tipo su un singolo elemento, in questo caso, un metodo. Ecco il codice approssimativo che sto lavorando con:Più annotazioni dello stesso tipo su un elemento?

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

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

Quando si compila quanto sopra, javac lamenta un'annotazione duplicato:

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

non è semplicemente possibile ripetere le annotazioni come questo? Pedanticamente parlando, le due istanze di @Foo non sono diverse a causa del fatto che i loro contenuti sono diversi?

Se quanto sopra non è possibile, quali sono alcuni possibili soluzioni?

AGGIORNAMENTO: Mi è stato chiesto di descrivere il mio caso d'uso. Ecco qui.

Sto costruendo un meccanismo sbrigativo di sintassi per "mappare" POJO per documentare negozi come MongoDB. Voglio consentire che gli indici siano specificati come annotazioni sui getter o setter. Ecco un esempio inventato:

public class Employee { 
    private List<Project> projects; 

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

Ovviamente, voglio essere in grado di trovare rapidamente le istanze di dipendenti da varie proprietà del progetto. Posso specificare @Index due volte con valori diversi di expr() o adottare l'approccio specificato nella risposta accettata. Anche se Hibernate fa questo e non è considerato un hack, penso che abbia ancora senso permettere almeno di avere più annotazioni dello stesso tipo su un singolo elemento.

+1

C'è sforzo per avere questa regola duplicata rilassarsi per consentire il programma in Java 7. Puoi descrivere il tuo caso d'uso per favore? – notnoop

+0

Ho modificato la mia domanda con una descrizione del perché voglio farlo. Grazie. –

+0

Potrebbe essere utile in CDI per consentire a un bean di essere fornito per più qualificatori. Ad esempio, ho appena provato a riutilizzare un bean in due punti qualificandolo "@Produces @PackageName (" test1 ") @PackageName (" test2 ")" –

risposta

127

Due o più annotazioni dello stesso tipo non sono consentite. Tuttavia, si potrebbe fare qualcosa di simile:

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

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

avrete bisogno di gestione dedicata di Foos annotazioni nel codice però.

btw, ho appena usato questa 2 ore fa per risolvere lo stesso problema :)

+2

Puoi farlo anche in Groovy? – Excel20

+5

@ Excel20 Sì. Dovresti usare parentesi quadre però, ad es. '@Foos ([@ Foo (bar =" uno "), @Foo (bar =" due ")])'. Vedi http://groovy.codehaus.org/Annotations+with+Groovy – sfussenegger

+0

Un po 'tardi nel corso della giornata, ma attenzione a indicare il consiglio che può elaborare l'elenco di Foo all'interno di Foos? Al momento sto provando a calcolare il risultato di un metodo ma, sebbene il Foos sia intercettato, il consiglio di Foo non è mai entrato –

12

Come detto da sfussenegger, questo non è possibile.

La solita soluzione è per creare un'annotazione "multipla", che gestisce un array della precedente annotazione. In genere viene chiamato lo stesso, con un suffisso "s".

A proposito, questo è molto usato in grandi progetti pubblici (Hibernate per esempio), quindi non dovrebbe essere considerato come un hack, ma piuttosto una soluzione corretta per questa esigenza.


A seconda delle esigenze, potrebbe essere meglio per permettere che la tua annotazione in precedenza per gestire più valori.

Esempio:

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

Sapevo che questo era stranamente familiare. Grazie per aver rinfrescato la mia memoria. –

+0

Ora è possibile con Java 8. – AnixPasBesoin

3

Se avete solo 1 parametro "bar" è possibile il nome come "valore". In questo caso non dovrete scrivere il nome del parametro a tutti quando si utilizza in questo modo:

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

un po 'più corto e più ordinato, imho ..

+0

Punto corretto, ma in che modo tenta di rispondere alla domanda dell'OP? – Mordechai

+0

@MouseEvent hai ragione, penso che sia stato più di un miglioramento della risposta superiore di sfussenegger e quindi appartiene più nei commenti lassù. Tuttavia, la risposta è obsoleta a causa di annotazioni ripetibili ... – mihahh

3

combinando le altre risposte nella forma più semplice ... un'annotazione con un semplice elenco di valori ...

11

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

Partendo da Java8 si può descrivere le annotazioni ripetibili:

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

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

Nota, value è un campo obbligatorio per la lista valori.

Ora è possibile utilizzare le annotazioni ripeterli invece di riempire la matrice:

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

parte gli altri modi citati, v'è un altro modo meno dettagliato 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{ 

} 

Esempio da predefinito ottiene, FooContainer come annotazione

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

Sia la sopra di stampa:

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

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

+0

Vale la pena sottolineare che nome metodo/campo in FooContainer deve essere rigorosamente denominato "value()". Altrimenti, Foo non verrà compilato. – Tomasz

+0

... anche contenente il tipo di annotazione (FooContainer) non può essere applicabile a più tipi rispetto al tipo di annotazione ripetibile (Foo). – Tomasz

Problemi correlati