Analyse des annotations Java à l’exécution

Quelle est la meilleure façon de rechercher l’ensemble d’une classe dans une classe annotée?

Je fais une bibliothèque et je veux autoriser les utilisateurs à annoter leurs classes, donc lorsque l’application Web démarre, je dois parsingr l’ensemble du chemin de classe pour certaines annotations.

Connaissez-vous une bibliothèque ou une installation Java pour faire cela?

Edit: je pense à quelque chose comme la nouvelle fonctionnalité pour les services Web Java EE 5 ou EJB. Vous @WebService votre classe avec @WebService ou @EJB et le système trouve ces classes pendant le chargement afin qu’elles soient accessibles à distance.

Utilisez org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider

API

Un fournisseur de composants qui parsing le chemin de classes à partir d’un package de base. Il applique ensuite des filtres d’exclusion et d’inclusion aux classes résultantes pour trouver des candidats.

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

Et une autre solution est Google reflections .

Examen rapide:

  • La solution Spring est la solution idéale si vous utilisez Spring. Sinon, c’est une grande dépendance.
  • Utiliser directement ASM est un peu lourd.
  • L’utilisation directe de Java Assist est également maladroite.
  • Annovention est super léger et pratique. Pas encore d’intégration de Maven.
  • Google reflections tire dans les collections Google. Indexe tout et est super rapide.

(Edit: FastClasspathScanner a maintenant été renommé en ClassGraph)

Essayez ClassGraph . (Disclaimer, je suis l’auteur). ClassGraph prend en charge l’parsing des annotations, à l’exécution ou au moment de la construction, mais aussi beaucoup plus. ClassGraph peut créer une représentation abstraite de tout le graphe de classe (toutes les classes, annotations, méthodes, parameters de méthode et champs) en mémoire, pour toutes les classes du classpath, ou pour les classes des packages inclus dans la liste blanche. tu veux. ClassGraph prend en charge plus de mécanismes de spécification de classpath et de chargeurs de classe que tout autre scanner, et fonctionne également de manière transparente avec le nouveau système de module JPMS, donc si vous basez votre code sur ClassGraph, votre code sera portable au maximum. Voir l’API ici.

Si vous voulez un poids très léger (pas de dépendances, API simple, fichier JAR de 15 Ko) et une solution très rapide , jetez un coup d’œil au annotation-detector disponible sur https://github.com/rmuller/infomas-asl

Disclaimer: Je suis l’auteur.

Vous pouvez utiliser l’API Java Pluggable Annotation Processing pour écrire le processeur d’annotation qui sera exécuté pendant le processus de compilation et collectera toutes les classes annotées et générera le fichier d’index pour une utilisation d’exécution.

C’est le moyen le plus rapide d’effectuer une découverte de classe annotée car vous n’avez pas besoin d’parsingr votre chemin de classe à l’exécution, ce qui est généralement très lent. En outre, cette approche fonctionne avec tous les chargeurs de classe et pas seulement avec les collecteurs URLClassL généralement pris en charge par les scanneurs d’exécution.

Le mécanisme ci-dessus est déjà implémenté dans la bibliothèque ClassIndex .

Pour l’utiliser, annotez votre annotation personnalisée avec la méta-annotation @IndexAnnotated . Cela créera au moment de la compilation un fichier d’index: META-INF / annotations / com / test / YourCustomAnnotation répertoriant toutes les classes annotées. Vous pouvez accéder à l’index lors de l’exécution en exécutant:

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

Utilisez le ServiceLoader ou implémentez le vôtre si vous n’êtes pas dans Java 6.

Un processeur d’annotation pourrait peut-être produire les fichiers nécessaires sous META-INF / services au moment de la compilation.

Essayez Scannotation .

Il peut être utilisé pour rechercher dans le répertoire classpath ou dans le répertoire lib de votre application Web des annotations spécifiques.

Vous voudrez peut-être utiliser http://code.google.com/p/annovention/

Légèrement hors-sujet, mais Spring fait aussi quelque chose de similaire, en utilisant , que vous pourriez peut-être étudier le code source de?

Spring permet de détecter automatiquement les classes «stéréotypées» […]. Pour détecter automatiquement ces classes et enregistrer les beans correspondants, il faut inclure l’élément [context: component-scan].

Avec Spring, vous pouvez également écrire ce qui suit en utilisant la classe AnnotationUtils. c’est à dire:

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

Pour plus de détails et toutes les différentes méthodes, consultez les documents officiels: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

Je ne suis pas sûr que cela vous aide ou non, mais vous pouvez regarder le projet apache commons-discovery.

projet de découverte

Est-il trop tard pour répondre? Je dirais, il vaut mieux aller par les bibliothèques comme ClassPathScanningCandidateComponentProvider ou comme Scannotations

Mais même après que quelqu’un a voulu essayer quelques mains avec classLoader, j’en ai écrit moi-même pour imprimer les annotations des classes dans un paquet:

 public class ElementScanner { public void scanElements(){ try { //Get the package name from configuration file Ssortingng packageName = readConfig(); //Load the classLoader which loads this class. ClassLoader classLoader = getClass().getClassLoader(); //Change the package structure to directory structure Ssortingng 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 

Et dans Config File, vous placez le nom du package et le démasquer dans une classe.

Java n’a pas de “découverte”. Le seul moyen que je connaisse est d’parsingr le répertoire dans lequel les fichiers .class doivent être, d’parsingr les noms et de l’utiliser. Horriblement moche, peut-être y a-t-il un meilleur paquet ces jours-ci – je n’ai pas regardé depuis quelques années.

Habituellement, ce problème était résolu en incluant un fichier de propriétés ou un fichier .xml contenant les noms de classe.

Je serais également intéressé par une meilleure réponse.

L’API Classloader n’a pas de méthode “énumérer”, car le chargement de classe est une activité “à la demande” – vous avez généralement des milliers de classes dans votre chemin de classe, dont une fraction seulement sera nécessaire (le rt.jar seul est de 48Mo aujourd’hui!).

Donc, même si vous pouviez énumérer toutes les classes, cela demanderait beaucoup de temps et de mémoire.

L’approche simple consiste à lister les classes concernées dans un fichier de configuration (XML ou tout ce qui vous convient); Si vous voulez le faire automatiquement, limitez-vous à un répertoire JAR ou à un répertoire de classe.

Google Reflections semble être beaucoup plus rapide que Spring. Trouvé cette demande de fonctionnalité qui répond à cette différence: http://www.opensaga.org/jira/browse/OS-738

C’est une raison d’utiliser Reflections car le temps de démarrage de mon application est vraiment important pendant le développement. Reflections semble également être très facile à utiliser pour mon cas d’utilisation (recherchez tous les implémenteurs d’une interface).

Si vous cherchez une alternative aux reflections, je vous recommande Panda Utilities – AnnotationsScanner . C’est un scanner sans Guava (Guava a ~ 3 Mo, Panda Utilities a environ 200 Ko) basé sur le code source de la bibliothèque de reflections.

Il est également dédié aux recherches futures. Si vous souhaitez parsingr plusieurs fois les sources incluses ou même fournir une API permettant à quelqu’un d’parsingr le ClassFiles actuel, AnnotationsScannerProcess met en cache tous les ClassFiles récupérés, ce qui le rend très rapide.

Exemple simple d’utilisation de AnnotationsScanner :

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

Si vous voulez une bibliothèque Scala, utilisez Sclasner: https://github.com/ngocdaothanh/sclasner