Java-Annotationen zur Laufzeit scannen

Was ist der beste Weg, den gesamten classnpfad nach einer annotierten class zu durchsuchen?

Ich mache eine Bibliothek und möchte den Benutzern erlauben, ihre classn zu kommentieren. Wenn die Webanwendung startet, muss ich den gesamten classnpfad nach bestimmten Anmerkungen durchsuchen.

Kennen Sie eine Bibliothek oder eine Java-Einrichtung, um dies zu tun?

Edit: Ich denke über etwas wie die neue functionalität für Java EE 5 Web Services oder EJBs nach. Sie kommentieren Ihre class mit @WebService oder @EJB und das System findet diese classn beim Laden, so dass sie remote erreichbar sind.

Verwenden Sie org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider

API

Ein Komponentenanbieter, der den classnpfad von einem Basispaket aus scannt. Es wendet dann exclude an und fügt Filter zu den resultierenden classn ein, um Kandidaten zu finden.

 ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(); scanner.addIncludeFilter(new AnnotationTypeFilter(.class)); for (BeanDefinition bd : scanner.findCandidateComponents()) System.out.println(bd.getBeanClassName()); 

Und eine andere Lösung ist Google Überlegungen .

Schnelle Überprüfung:

  • Spring-Lösung ist der Weg zu gehen, wenn Sie Spring verwenden. Ansonsten ist es eine große Abhängigkeit.
  • Die Verwendung von ASM ist ein wenig mühsam.
  • Die direkte Verwendung von Java Assist ist ebenfalls schwerfällig.
  • Annovention ist superleicht und bequem. Noch keine Maven-Integration.
  • Google Reflections zieht Google-Sammlungen ein. Indexiert alles und ist dann super schnell.

(Bearbeiten: FastClaspathScanner wurde jetzt in ClassGraph umbenannt)

Probieren Sie ClassGraph aus . (Disclaimer, ich bin der Autor). ClassGraph unterstützt Annotations-Scans, entweder zur Laufzeit oder zum Zeitpunkt der Erstellung, aber auch viel mehr. ClassGraph kann eine abstrakte Darstellung des gesamten classngraphen (alle classn, Annotationen, Methoden, Methodenparameter und Felder) im Speicher für alle classn im classnpfad oder für classn in Paketen auf der weißen Liste erstellen, und Sie können diesen classngraphen jedoch abfragen Sie wollen. ClassGraph unterstützt mehr classnpfad-Spezifikationsmechanismen und classnlader als jeder andere Scanner und arbeitet auch nahtlos mit dem neuen JPMS-Modulsystem zusammen. Wenn Sie Ihren Code auf ClassGraph aufbauen, wird Ihr Code maximal tragbar sein. Siehe die API hier.

Wenn Sie ein wirklich geringes Gewicht (keine Abhängigkeiten, einfache API, 15-KB-JAR-Datei) und sehr schnelle Lösung wollen, casting Sie einen Blick auf annotation-detector gefunden unter https://github.com/rululer/infomas-asl

Haftungsausschluss: Ich bin der Autor.

Sie können die API für die verarbeitbare Annotation von Java verwenden, um Annotationsprozessoren zu schreiben, die während des Kompilierungsprozesses ausgeführt werden, und alle mit Annotationen versehenen classn sammeln und die Indexdatei zur Laufzeit erstellen.

Dies ist der schnellste Weg, um eine annotierte classnerkennung durchzuführen, da Sie Ihren classnpfad nicht zur Laufzeit scannen müssen, was normalerweise ein sehr langsamer Vorgang ist. Dieser Ansatz funktioniert auch mit jedem Classloader und nicht nur mit URLClassLoadern, die normalerweise von Runtime-Scannern unterstützt werden.

Der obige Mechanismus ist bereits in der ClassIndex- Bibliothek implementiert.

Um sie zu verwenden, versehen Sie Ihre benutzerdefinierte Annotation mit @IndexAnnotierter Meta-Annotation. Dies erstellt zur Kompilierzeit eine Indexdatei: META-INF / annotations / com / test / YourCustomAnnotation, die alle annotierten classn auflistet. Sie können den Index zur Laufzeit aufrufen, indem Sie Folgendes ausführen:

 ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class) 

Verwenden Sie den ServiceLoader oder implementieren Sie Ihren eigenen, wenn Sie nicht in Java 6 sind.

Vielleicht könnte ein Annotationsprozessor zur Kompilierung die notwendigen Dateien unter META-INF / services erzeugen.

Versuchen Sie Scannotation .

Es kann verwendet werden, um den classnpfad oder das Verzeichnis Ihrer Webanwendungsbibliothek nach bestimmten Anmerkungen zu durchsuchen.

Vielleicht möchten Sie http://code.google.com/p/annovention/ verwenden

Etwas offtopic, aber Spring macht auch etwas ähnliches, mit , mit dem man vielleicht den Quellcode von?

Spring bietet die Möglichkeit, “stereotype” classn automatisch zu erkennen […]. Um diese classn automatisch zu erkennen und die entsprechenden Beans zu registrieren, muss das [context: component-scan-Element] eingefügt werden.

Mit Spring können Sie auch einfach folgendes mit der AnnotationUtils-class schreiben. zB:

 Class< ?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null); 

Für weitere Details und alle verschiedenen Methoden überprüfen Sie die offiziellen Dokumente: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

Ich bin mir nicht sicher, ob es dir helfen wird oder nicht, aber du könntest dir das Apache Commons-Discovery-Projekt ansehen.

Entdeckungsprojekt

Ist es zu spät, um zu antworten? Ich würde sagen, es ist besser, an Bibliotheken wie ClassPathScanningCandidateComponentProvider oder ähnliche Scannotations zu gehen

Aber selbst wenn jemand mit classLoader etwas ausprobieren möchte, habe ich selbst einige geschrieben, um die Anmerkungen aus den classn in einem Paket zu drucken:

 public class ElementScanner { public void scanElements(){ try { //Get the package name from configuration file String packageName = readConfig(); //Load the classLoader which loads this class. ClassLoader classLoader = getClass().getClassLoader(); //Change the package structure to directory structure String packagePath = packageName.replace('.', '/'); URL urls = classLoader.getResource(packagePath); //Get all the class files in the specified URL Path. File folder = new File(urls.getPath()); File[] classes = folder.listFiles(); int size = classes.length; List> classList = new ArrayList>(); for(int i=0;i repoClass; repoClass = Class.forName(classNamePath); Annotation[] annotations = repoClass.getAnnotations(); for(int j =0;j 

Und in Config-Datei, legen Sie den Paketnamen und unmarshall es zu einer class.

Java hat keine “Discovery”. Der einzige Weg, den ich kenne, besteht darin, das Verzeichnis zu durchsuchen, in dem sich die .class-Dateien befinden sollen, die Namen zu analysieren und diese zu verwenden. Schrecklich hässlich, vielleicht gibt es heutzutage ein besseres Paket – ich habe nicht in ein paar Jahren gesucht.

In der Regel wurde dieses Problem behoben, indem eine Eigenschaftendatei oder eine XML-Datei mit den darin enthaltenen classnnamen hinzugefügt wurde.

Ich wäre daran interessiert, eine bessere Antwort zu hören.

Die Classloader-API hat keine “Enumerate” -Methode, da das Laden von classn eine “On-Demand” -Aktivität ist – normalerweise haben Sie Tausende von classn in Ihrem classnpfad, von denen nur ein Bruchteil jemals benötigt wird (rt.jar) alleine ist heute 48MB!).

Selbst wenn Sie alle classn aufzählen könnten , wäre dies sehr zeit- und speicheraufwendig.

Der einfache Ansatz besteht darin, die betroffenen classn in einer Setup-Datei aufzulisten (xml oder was immer Ihnen gefällt); Wenn Sie dies automatisch tun möchten, beschränken Sie sich auf ein JAR- oder ein classnverzeichnis.

Google Reflections scheint viel schneller zu sein als Spring. Habe diese Feature-Anfrage gefunden, die auf diesen Unterschied hinweist: http://www.opensaga.org/jira/browse/OS-738

Dies ist ein Grund, reflectionen zu verwenden, da die Startzeit meiner Anwendung während der Entwicklung sehr wichtig ist. Reflections scheint auch für meinen Anwendungsfall sehr einfach zu sein (finde alle Implementierer einer Schnittstelle).

Wenn Sie nach einer Alternative zu Reflektionen suchen, empfehle ich Panda Utilities – AnnotationsScanner . Es ist ein Guava-frei (Guava hat ~ 3MB, Panda Utilities hat ~ 200kb) Scanner basierend auf der reflection Bibliothek Quellcode.

Es ist auch für zukünftige Suchanfragen gedacht. Wenn Sie mehrere Quelltexte mehrfach scannen ClassFiles oder sogar eine API zur Verfügung stellen ClassFiles , die es ermöglicht, den aktuellen classnpfad zu ClassFiles , ClassFiles AnnotationsScannerProcess alle abgerufenen ClassFiles und ist somit sehr schnell.

Einfaches Beispiel für die Verwendung von AnnotationsScanner :

 AnnotationsScanner scanner = AnnotationsScanner.createScanner() .includeSources(ExampleApplication.class) .build(); AnnotationsScannerProcess process = scanner.createWorker() .addDefaultProjectFilters("net.dzikoysk") .fetch(); Set> classes = process.createSelector() .selectTypesAnnotatedWith(AnnotationTest.class); 

Wenn Sie eine Scala-Bibliothek benötigen, verwenden Sie Sclasner: https://github.com/ngocdaothanh/slasner