2012-04-10 1 views
18

sagen, dass ich eine Anmerkung mit einer Eigenschaft haben:Passing Annotation Eigenschaften Meta-Annotationen

@Named(name = "Steve") 
private Person person 

und ich möchte eine Verbindung Annotation mit mehreren Meta-Annotationen erstellen, einschließlich der, die eine Eigenschaft

nimmt
@Named 
@AnotherAnnotation 
@YetAnotherAnnotation 
public @interface CompoundAnnotation { 

    ... 
} 

Gibt es eine Möglichkeit, dass ich Eigenschaften an die zusammengesetzte Annotation zu einer der Meta-Annotationen übergeben kann?

Eg, etwa wie folgt:

@CompoundAnnotation(name = "Bob") 
private Person person; 

, die gleichwertig ist, aber viel bequemer als

@Named(name = "Bob") 
@AnotherAnnotation 
@YetAnotherAnnotation 
private Person person; 

Dank!

PS Entschuldigung für meine schlechte Wahl einer Beispiel Annotation - ich hatte nicht die javax.inject. @ Named Annotation im Hinterkopf, nur einige willkürliche Annotation, die Eigenschaften hat.


Vielen Dank für Ihre Antworten/Kommentare.

Es scheint definitiv der Fall zu sein, dass dies nicht möglich ist. Es passiert jedoch einfach, dass es für meinen Fall-in-Punkt eine einfache Problemlösung gibt, die ich weitergeben werde, falls es jemandem hilft:

Ich arbeite mit Spring und möchte meine eigenen Annotationen erstellen, die @ haben Komponente als Meta-Annotation, also automatisch durch Komponenten-Scan erkannt. Ich wollte jedoch auch die BeanName-Eigenschaft (entsprechend der Werteigenschaft in @Component) festlegen können, damit ich benutzerdefinierte Bean-Namen haben kann.

Nun stellt sich heraus, dass die nachdenklichen Jungs von Spring es möglich gemacht haben, genau das zu tun - der AnnotationBeanNameGenerator wird die 'value' Eigenschaft der übergebenen Annotation übernehmen und diese als Bean Name verwenden (und natürlich, Standardmäßig erhält es nur übergebene Annotationen, die @Component sind oder @Component als Meta-Annotation haben. Im Nachhinein sollte dies für mich von Anfang an klar gewesen sein - so können vorhandene Annotationen mit @Component als Meta-Annotation, wie @Service und @Registry, Bean-Namen liefern.

Hoffen, dass das für jemanden nützlich ist. Ich finde es immer noch eine Schande, dass dies nicht generell möglich ist!

+0

Ich sehe nicht, wie, es sei denn, Sie hinzufügen Anmerkungen über Byte-Code-Manipulation zum Zeitpunkt des Ladens. (Oder ein benutzerdefinierter Annotationsprozessor, nehme ich an.) Neugierig zu sehen, was alles ohne Tricks möglich ist. –

+0

Wenn Sie hier nur laut nachdenken, wird das keine Umgehungslösung sein, wenn Sie eine Basisklasse mit AnotherAnnotation und YAA haben und die Person-Klasse das erweitert? Schau dir auch Reflections an, vielleicht bekommst du ein paar Ideen: http://code.google.com/p/reflections/ – maksimov

+0

Bezogen auf http://stackoverflow.com/questions/1624084/why-is-not-possible- zu-erweitern-Anmerkungen-in-Java – Gray

Antwort

6

Gibt es eine Möglichkeit, dass ich Eigenschaften an die zusammengesetzte Annotation zu einer der Meta-Annotationen übergeben kann?

Ich denke, die einfache Antwort ist "Nein". Es gibt keine Möglichkeit, Person zu fragen, welche Anmerkungen es darauf hat und beispielsweise @Named erhalten.

Die komplexere Antwort ist, dass Sie Annotationen verketten können, aber Sie müssten diese Anmerkungen durch Reflexion untersuchen.Zum Beispiel sind die folgenden Werke:

@Bar 
public class Foo { 
    public static void main(String[] args) { 
     Annotation[] fooAnnotations = Foo.class.getAnnotations(); 
     assertEquals(1, fooAnnotations.length); 
     for (Annotation annotation : fooAnnotations) { 
      Annotation[] annotations = 
       annotation.annotationType().getAnnotations(); 
      assertEquals(2, annotations.length); 
      assertEquals(Baz.class, annotations[0].annotationType()); 
     } 
    } 

    @Baz 
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface Bar { 
    } 

    @Retention(RetentionPolicy.RUNTIME) 
    public @interface Baz { 
    } 
} 

jedoch die folgende Anweisung den Wert null zurück:

// this always returns null 
Baz baz = Foo.class.getAnnotation(Baz.class) 

Das bedeutet, dass jede dritte Partei-Klasse, die für die @Baz Anmerkung sucht, wird es nicht sehen.

14

Es ist ein paar Jahre später nun, und da Sie verwenden Spring, was Sie fordern ist eine Art nun möglich, die @AliasFor Annotation verwenden.

Zum Beispiel:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
@SpringApplicationConfiguration 
@ActiveProfiles("test") 
public @interface SpringContextTest { 

    @AliasFor(annotation = SpringApplicationConfiguration.class, attribute = "classes") 
    Class<?>[] value() default {}; 

    @AliasFor("value") 
    Class<?>[] classes() default {}; 
} 

Jetzt können Sie Ihren Test mit @SpringContextTest(MyConfig.class), und das Erstaunliche ist, mit Anmerkungen versehen, dass es tatsächlich so funktioniert, die man erwarten würde.