2009-10-12 15 views
75

Estoy intentando copiar dos o más anotaciones del mismo tipo en un solo elemento, en este caso, un método. Aquí está el código aproximada que estoy trabajando con:Anotaciones múltiples del mismo tipo en un elemento?

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

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

Al compilar lo anterior, javac se queja de una anotación de duplicado:

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

¿Es simplemente no es posible repetir las anotaciones de este tipo? Pedadicamente hablando, ¿no son las dos instancias de @Foo superiores diferentes debido a que sus contenidos son diferentes?

Si lo anterior no es posible, ¿cuáles son algunas soluciones posibles?

ACTUALIZACIÓN: Me han pedido que describa mi caso de uso. Aquí va.

Estoy construyendo un mecanismo de sintaxis azucarada para "mapear" POJOs para documentar tiendas como MongoDB. Quiero permitir que los índices se especifiquen como anotaciones en los getters o setters. Aquí está un ejemplo artificial:

public class Employee { 
    private List<Project> projects; 

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

Obviamente, quiero ser capaz de encontrar rápidamente las instancias de la plantilla por varias propiedades del proyecto. Puedo especificar @Index dos veces con diferentes valores de expr() o tomar el enfoque especificado en la respuesta aceptada. Aunque Hibernate hace esto y no se considera un hack, creo que todavía tiene sentido permitir al menos tener varias anotaciones del mismo tipo en un solo elemento.

+1

Hay una esfuerzo para que esta regla duplicada se relaje para permitir su programa en Java 7. ¿Puede describir su caso de uso, por favor? – notnoop

+0

He editado mi pregunta con una descripción de por qué quiero hacer esto. Gracias. –

+0

Podría ser útil en CDI para permitir que se proporcione un frijol para múltiples calificadores. Por ejemplo, acabo de intentar reutilizar un bean en dos lugares calificándolo "@Produces @PackageName (" test1 ") @PackageName (" test2 ")" –

Respuesta

127

No se permiten dos o más anotaciones del mismo tipo. Sin embargo, se podría hacer algo como esto:

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

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

que necesitará un manejo especializado de Foos anotación en el código sin embargo.

por cierto, he acabo de utilizar este hace 2 horas para solucionar el mismo problema :)

+2

¿Puedes hacer esto también en Groovy? – Excel20

+5

@ Excel20 Sí. Sin embargo, debería usar corchetes, p. '@Foos ([@ Foo (bar =" uno "), @Foo (bar =" dos ")])'. Ver http://groovy.codehaus.org/Annotations+with+Groovy – sfussenegger

+0

Un poco tarde en el día, pero se preocupan por señalar los consejos que pueden procesar la lista de Foo dentro de Foos. Por el momento estoy tratando de procesar el resultado de un método, pero aunque el Foos es interceptado, el consejo de Foo nunca se ingresa –

12

Como dijo por sfussenegger, esto no es posible.

La solución habitual es crear una anotación "múltiple", que maneja una matriz de la anotación anterior. Suele llamarse igual, con un sufijo 's'.

Por cierto, esto es muy utilizado en grandes proyectos públicos (Hibernate, por ejemplo), por lo que no se debe considerar como un hack, sino como una solución correcta para esta necesidad.


Dependiendo de sus necesidades, podría ser mejor permita que su anotación anterior para manejar múltiples valores.

Ejemplo:

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

. Sabía que esto era inquietantemente familiar. Gracias por refrescar mi memoria. –

+0

Ahora es posible con Java 8. – AnixPasBesoin

3

Si sólo tiene un "bar" 1 parámetro que puede nombrar como "valor". En este caso, usted no tiene que escribir el nombre del parámetro en absoluto cuando se utiliza de esta manera:

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

un poco más corto y más ordenado, en mi humilde opinión ..

+0

Punto correcto, pero ¿cómo intenta responder a la pregunta de OP? – Mordechai

+0

@MouseEvent tienes razón, creo que fue más una mejora de la respuesta principal de sfussenegger y por lo tanto pertenece más a los comentarios de allí. Pero la respuesta está desactualizada de todos modos debido a las anotaciones repetibles ... – mihahh

3

combinando las otras respuestas en la forma más simple ... una anotación con una simple lista de los valores ...

11

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

A partir de Java8 se puede describir anotaciones repetibles:

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

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

Nota, value es un campo obligatorio para la lista de valores.

Ahora usted puede utilizar las anotaciones repetición de ellas en lugar de llenar la matriz:

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

Aparte de las otras formas mencionadas, existe una forma más menos detallado en 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{ 

} 

ejemplo, por por defecto se pone, FooContainer como una anotación

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

Tanto el por encima de impresión:

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

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

+0

Vale la pena señalar que el nombre del método/campo en FooContainer tiene que ser estrictamente llamado "valor()". De lo contrario, Foo no compilará. – Tomasz

+0

... que también contiene el tipo de anotación (FooContainer) no puede aplicarse a más tipos que el tipo de anotación repetible (Foo). – Tomasz

Cuestiones relacionadas