2012-04-01 5 views
0

Angenommen, ich habe diese AnmerkungSuchen in allen Instanzen bestimmter Annotationstyp

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface Name 
{ 
    String value(); 
} 

Diese verwendet werden wird wie folgt

@Name("name1") 
public static Foo foo = new Foo(); 

I Vielfachen davon über mein Projekt Quelldateien. Gibt es eine ziemlich einfache Möglichkeit, all diese "foo" s zu suchen und zu sammeln, denen @Name vorausgeht? Mit anderen Worten, ich möchte eine Methode schreiben, die eine Set<Foo> zurückgeben würde, die diese enthält.

Danke !!!

+0

In Java? Unix cmd Zeile verwenden sollte ziemlich einfach mit find + grep – ControlAltDel

+0

@ user1291492 sein, die Beibehaltung ist RUNTIME. Die Methode kann Zugriff auf den Quellcode haben oder nicht. OTH, vielleicht ist die Klassendatei übergreifbar. – emory

+0

Etwas off-topic, aber warum willst du ein 'Set '. Es scheint sinnvoller zu sein, eine "Map " oder was ist der Sinn des Namens zu haben. – emory

Antwort

2

Ich bin nicht wirklich vertraut mit den Klassenpfad-Scanner, die andere vorschlagen. Sie scheinen eine robuste - wenn nicht ideale - Lösung zu sein.

Wenn Sie die Kontrolle über die Quelle haben, können Sie die Annotationsverarbeitung verwenden.

Erstellen Sie einen Annotationsprozessor, der eine Klasse - MapClass mit einem statischen Element Map<String,Foo> erstellt. Jedes Mal, wenn der Annotationsprozessor auf die Annotation @Name stößt, fügt er diese dem Quellcode MapClass hinzu. Wenn die Verarbeitung der Anmerkungen abgeschlossen ist, hat dies denselben Effekt, als ob Sie die Karte fest codiert hätten.

Die Annotationsverarbeitung erfolgt während der Kompilierungszeit. Wenn einige der Klassen in Ihrem Projekt nicht von Ihnen kompiliert werden. Zum Beispiel, wenn jemand anderes einige Klassen kompiliert und Ihnen ein Glas gibt, dann wird es nicht so einfach funktionieren. Aber wenn alle Klassen von Ihnen kompiliert werden, sollte das kein Problem sein.

Um einen Annotationsprozessor zu erstellen, erweitern Sie AbstractProcessor. Sie sollten Ihre Klasse mit einer @ SupportedAnnotationTypes ("Name") Annotation annotieren (stellen Sie sicher, dass name der vollständig qualifizierte Name Ihrer Annotation ist).

Überschreiben Sie die process Methode. process hat zwei Parameter: annotations und roundEnv. annotations ist nur der Satz von Anmerkungen, die dieser bestimmte Prozessor unterstützt - in Ihrem Fall sollte es (Name) sein. roundEnv ist eine nützliche Dienstprogrammklasse.

Iterieren Sie durch die eine Anmerkung in annotations. Verwenden Sie roundEnv bis getElementsAnnotatedWith. Dies sollte Ihnen die Menge aller Elemente geben, die die @Name Annotation tragen.

AbstractProcessor hat ein anderes Dienstprogramm Mitglied - processingEnv. Verwenden Sie die getFiler-Methode zu createSourceFile.

Dann müssen Sie Ihre Zusammenstellung ein wenig ändern. Sie müssen Ihren Prozessor separat und vor den anderen Klassen kompilieren. Nachdem der Prozessor kompiliert wurde und Sie die anderen Klassen kompilieren, müssen Sie den Compiler über Ihren Prozessor informieren. Wenn Sie die Befehlszeile verwenden, fügen Sie -processorpath /path/to/processor/class[es] und -processor qualified.name.of.processor hinzu.

Die Vorteile dieses Ansatzes gegenüber dem Klassenpfad-Scanner sind, dass alles zur Kompilierzeit passiert. Wenn Sie beispielsweise versehentlich eine @Name Annotation zu einem Bar Element hinzufügen, kann der Prozessor einen Kompilierzeitfehler auslösen (wenn Sie möchten, dass der Prozessor ihn ignorieren kann). Dann können Sie es reparieren, bevor das Produkt versendet. Bei einem Klassenpfad-Scanner ist jeder Fehler ein Laufzeitfehler - der dem Benutzer angezeigt wird.

Der Nachteil dieses Ansatzes ist auch, dass alles zur Kompilierzeit passiert. Dies erschwert das dynamische Hinzufügen von Klassen zum Projekt.

+0

Das klingt nach dem, was ich brauche. Aber wie genau würde der Annotationsprozessor aussehen? Und ich bin mir nicht sicher, wie es auf die @Name Annotation stoßen kann? Wäre es nicht noch nötig, etwas zu scannen, um diese zu finden? – user113454

+0

Könnten Sie bitte näher ausführen? Danke – user113454

+0

@ user1064918 Ich hoffe, dass hilft. Ich denke, der große Unterschied ist, dass der Klassenpfad-Scanner robuster ist - er wird einfach funktionieren. Wenn Ihr Projekt jedoch geeignet ist, kann die Verwendung eines Annotationsprozessors sinnvoller sein. – emory

0

Nein, nicht wirklich (nicht aus dem Code). Eine Lösung wäre, sie alle in einer Klasse zu setzen, und dann iterieren auf den Field s (getFields()) der Klasse und prüfen, ob Annotation s (getAnnotation())

1

Was Sie brauchen, ist ein Classpath-Scanner ist. Ich habe Metapossum Scanner (es gewann, weil es in der MVN Repo ist) verwendet, um nach annotierten Klassen zu suchen, aber ich glaube nicht, dass es nach annotierten Feldern suchen würde. Die andere Option, die ich untersuchte, war Reflections. Ich habe Reflections nicht verwendet, sondern nur recherchiert. Die Dokumentation hat eine getFieldsAnnotatedWith Abfrage, die scheint, was Sie brauchen.

Seien Sie gewarnt, die Classpath-Scanner sind sloooow und werden immer sloower, je mehr Sie in Ihrem Classpath haben.

0

Vielleicht möchten Sie sehen Scannotation! Es kann dein Problem lösen !!!

Scannotation ist eine Java-Bibliothek, die eine Anmerkungsdatenbank aus einer Gruppe von .class-Dateien erstellt. Diese Datenbank besteht eigentlich nur aus einer Reihe von Maps, die angeben, welche Annotationen verwendet werden und welche Klassen sie verwenden.

PS .: VRaptor framework verwendet es intern!

Verwandte Themen