Est-il possible de trouver toutes les classes ou interfaces dans un package donné? (En regardant rapidement par exemple Package
, il semblerait que non.)
java
reflection
packages
Jonik
la source
la source
Réponses:
En raison de la nature dynamique des chargeurs de classe, cela n'est pas possible. Les chargeurs de classe ne sont pas tenus d'indiquer à la machine virtuelle les classes qu'elle peut fournir, à la place, il s'agit simplement de demandes de classes et doivent renvoyer une classe ou lever une exception.
Cependant, si vous écrivez vos propres chargeurs de classe, ou examinez les chemins de classe et ses jars, il est possible de trouver ces informations. Cependant, cela se fera via les opérations du système de fichiers, et non par réflexion. Il peut même y avoir des bibliothèques qui peuvent vous y aider.
S'il y a des classes qui sont générées ou livrées à distance, vous ne pourrez pas découvrir ces classes.
La méthode normale consiste plutôt à enregistrer quelque part les classes auxquelles vous devez accéder dans un fichier, ou à les référencer dans une classe différente. Ou utilisez simplement la convention quand il s'agit de nommer.
Addendum: La bibliothèque Reflections vous permettra de rechercher des classes dans le chemin de classe actuel. Il peut être utilisé pour obtenir toutes les classes dans un package:
la source
Vous devriez probablement jeter un œil à la bibliothèque Open Source Reflections . Avec lui, vous pouvez facilement réaliser ce que vous voulez.
Tout d'abord, configurez l'index de réflexions (c'est un peu compliqué car la recherche de toutes les classes est désactivée par défaut):
Ensuite, vous pouvez interroger tous les objets d'un package donné:
la source
.addUrls(ClasspathHelper.forJavaClassPath())
place des solutions ci-dessus les a résolus pour moi. Moins de code aussi!Google Guava 14 comprend une nouvelle classe
ClassPath
avec trois méthodes pour rechercher des classes de niveau supérieur:getTopLevelClasses()
getTopLevelClasses(String packageName)
getTopLevelClassesRecursive(String packageName)
Voir les
ClassPath
javadocs pour plus d'informations.la source
ClassPath
est étiqueté avec@Beta
, donc ce pourrait ne pas être une bonne idée pour certains ...Vous pouvez utiliser cette méthode 1 qui utilise le
ClassLoader
.__________
1 Cette méthode a été tirée à l'origine de http://snippets.dzone.com/posts/show/4831 , qui a été archivée par Internet Archive, comme liée à maintenant. L'extrait est également disponible sur https://dzone.com/articles/get-all-classes-within-package .
la source
%20
, mais lenew File()
constructeur a traité cela comme un signe de pourcentage littéral deux zéro. Je l'ai corrigé en changeant ladirs.add(...)
ligne en ceci:dirs.add(new File(resource.toURI()));
Cela signifiait également que je devais ajouterURISyntaxException
à la clause throws degetClasses
Printemps
Cet exemple concerne Spring 4, mais vous pouvez également trouver le scanner de chemin de classe dans les versions antérieures.
Google Guava
Remarque: Dans la version 14, l'API est toujours marquée comme @Beta , donc méfiez-vous dans le code de production.
la source
ClassPath
classe de Guava est également marquée avec@Beta
: "Les API marquées de l'annotation @Beta au niveau de la classe ou de la méthode sont susceptibles de changer. Elles peuvent être modifiées de quelque manière que ce soit, voire supprimées, dans n'importe quelle version majeure. Si votre code est une bibliothèque elle-même (c'est-à-dire qu'elle est utilisée sur le CLASSPATH des utilisateurs hors de votre contrôle), vous ne devez pas utiliser les API bêta, sauf si vous les reconditionnez ... " code.google.com/p/guava-libraries/#Important_WarningsgetAllClasses()
méthode peut être utilisée.Bonjour. J'ai toujours eu des problèmes avec les solutions ci-dessus (et sur d'autres sites).
En tant que développeur, je programme un addon pour une API. L'API empêche l'utilisation de bibliothèques externes ou d'outils tiers. La configuration consiste également en un mélange de code dans des fichiers jar ou zip et des fichiers de classe situés directement dans certains répertoires. Mon code devait donc pouvoir fonctionner autour de chaque configuration. Après beaucoup de recherches, j'ai trouvé une méthode qui fonctionnera dans au moins 95% de toutes les configurations possibles.
Le code suivant est fondamentalement la méthode overkill qui fonctionnera toujours.
Le code:
Ce code analyse un package donné pour toutes les classes qui y sont incluses. Cela ne fonctionnera que pour toutes les classes dans le courant
ClassLoader
.Ces trois méthodes vous permettent de trouver toutes les classes dans un package donné.
Vous l'utilisez comme ceci:
L'explication:
La méthode obtient d'abord le courant
ClassLoader
. Il récupère ensuite toutes les ressources qui contiennent ledit package et répète cesURL
s. Il crée ensuite unURLConnection
et détermine le type d'URl que nous avons. Il peut s'agir d'un répertoire (FileURLConnection
) ou d'un répertoire dans un fichier jar ou zip (JarURLConnection
). Selon le type de connexion dont nous disposons, deux méthodes différentes seront appelées.Voyons d'abord ce qui se passe si c'est un
FileURLConnection
.Il vérifie d'abord si le fichier transmis existe et s'il s'agit d'un répertoire. Si tel est le cas, il vérifie s'il s'agit d'un fichier de classe. Si c'est le cas, un
Class
objet sera créé et placé dans leArrayList
. S'il ne s'agit pas d'un fichier de classe mais d'un répertoire, nous le parcourons simplement et faisons la même chose. Tous les autres cas / fichiers seront ignorés.Si
URLConnection
c'est un,JarURLConnection
l'autre méthode d'assistance privée sera appelée. Cette méthode parcourt toutes les entrées de l'archive zip / jar. Si une entrée est un fichier de classe et se trouve à l'intérieur du package, unClass
objet sera créé et stocké dans leArrayList
.Une fois que toutes les ressources ont été analysées, elle (la méthode principale) renvoie le
ArrayList
contenu de toutes les classes du package donné, que le courantClassLoader
connaît.Si le processus échoue à un moment donné, un
ClassNotFoundException
message contenant des informations détaillées sur la cause exacte sera affiché.la source
sun.net.www.protocol.file.FileURLConnection
, ce qui génère un avertissement au moment de la compilation ("avertissement: sun.net.www.protocol.file.FileURLConnection est l'API propriétaire de Sun et pourra être supprimé dans une version ultérieure"). Existe-t-il une alternative à l'utilisation de cette classe, ou l'avertissement peut-il être supprimé à l'aide d'annotations?if ( ... instanceof JarURLConnecton) { ... } else { // Asume that the Connection is valid and points to a File }
c'est ce que j'ai fait sur mon code pour rechercher des classes annotées JPASans utiliser de bibliothèques supplémentaires:
la source
upackage
c'estnull
... :(String pack = getPackage().getName();
, vous devez ajouterpack = pack.replaceAll("[.]", "/");
En général, les chargeurs de classe ne permettent pas de parcourir toutes les classes sur le chemin de classe. Mais généralement, le seul chargeur de classe utilisé est UrlClassLoader à partir duquel nous pouvons récupérer la liste des répertoires et des fichiers jar (voir getURLs ) et les ouvrir un par un pour répertorier les classes disponibles. Cette approche, appelée analyse de chemin de classe, est implémentée dans Scannotation and Reflections .
Une autre approche consiste à utiliser l' API Java Pluggable Annotation Processing pour écrire un processeur d'annotations qui collectera toutes les classes annotées au moment de la compilation et construira le fichier d'index pour une utilisation à l'exécution. Ce mécanisme est implémenté dans la bibliothèque ClassIndex :
Notez qu'aucune configuration supplémentaire n'est nécessaire car l'analyse est entièrement automatisée grâce au compilateur Java qui détecte automatiquement tous les processeurs trouvés sur le chemin de classe.
la source
Le mécanisme le plus robuste pour répertorier toutes les classes dans un package donné est actuellement ClassGraph , car il gère le plus large éventail possible de mécanismes de spécification de chemin de classe, y compris le nouveau système de modules JPMS. (Je suis l'auteur.)
la source
Voici comment je le fais. J'analyse tous les sous-dossiers (sous-packages) et je n'essaye pas de charger des classes anonymes:
la source
J'ai mis en place un projet github simple qui résout ce problème:
https://github.com/ddopson/java-class-enumerator
Cela devrait fonctionner pour les DEUX chemins de classe basés sur les fichiers ET pour les fichiers jar.
Si vous exécutez «make» après avoir extrait le projet, il l'imprimera:
Voir aussi mon autre réponse
la source
Oui, en utilisant quelques API, vous pouvez, voici comment j'aime le faire, face à ce problème que j'utilisais en mode hibernate core et j'ai dû trouver des classes qui étaient annotées avec une certaine annotation.
Faites-en une annotation personnalisée à l'aide de laquelle vous marquerez les classes que vous souhaitez choisir.
Puis marquez votre classe avec comme
Faites cette classe utilitaire qui a la méthode suivante
Appelez la méthode allFoundClassesAnnotatedWithEntityToBeScanned () pour obtenir un ensemble de classes trouvé.
Vous aurez besoin des bibliothèques fournies ci-dessous
la source
Vous devez rechercher chaque entrée de chargeur de classe dans le chemin de classe:
Si l'entrée est un répertoire, recherchez simplement dans le sous-répertoire de droite:
Si l'entrée est le fichier et qu'il s'agit d'un fichier jar, inspectez les entrées ZIP de celui-ci:
Maintenant, une fois que vous avez tous les noms de classe avec package, vous pouvez essayer de les charger avec réflexion et analyser s'il s'agit de classes ou d'interfaces, etc.
la source
J'ai essayé d'utiliser la bibliothèque Reflections, mais j'ai eu quelques problèmes à l'utiliser, et il y avait trop de pots que je devrais inclure juste pour obtenir simplement les classes sur un package.
Je posterai une solution que j'ai trouvée dans cette question en double: Comment obtenir tous les noms de classes dans un package?
La réponse a été écrite par sp00m ; J'ai ajouté quelques corrections pour le faire fonctionner:
Pour l'utiliser, il suffit d'appeler la méthode find comme sp00n mentionnée dans cet exemple: j'ai ajouté la création d'instances des classes si nécessaire.
la source
Je viens d'écrire une classe util, elle inclut des méthodes de test, vous pouvez vérifier ~
IteratePackageUtil.java:
la source
La solution d'Aleksander Blomskøld n'a pas fonctionné pour moi pour les tests paramétrés
@RunWith(Parameterized.class)
lors de l'utilisation de Maven. Les tests ont été nommés correctement et ont également été trouvés mais pas exécutés:Un problème similaire a été signalé ici .
Dans mon cas,
@Parameters
c'est la création d'instances de chaque classe dans un package. Les tests ont bien fonctionné lorsqu'ils étaient exécutés localement dans l'EDI. Cependant, lors de l'exécution de Maven, aucune classe n'a été trouvée avec la solution d'Aleksander Blomskøld.Je l'ai fait fonctionner avec les extraits suivants qui ont été inspirés par le commentaire de David Pärsson sur la réponse d'Aleksander Blomskøld:
la source
Et ça:
Vous pouvez alors surcharger la fonction:
Si vous devez le tester:
Si votre IDE n'a pas d'aide à l'importation:
Ça marche:
de votre IDE
pour un fichier JAR
sans dépendances externes
la source
Presque toutes les réponses utilisent
Reflections
ou lisent les fichiers de classe du système de fichiers. Si vous essayez de lire des classes à partir du système de fichiers, vous pouvez obtenir des erreurs lorsque vous empaquetez votre application au format JAR ou autre. Vous pouvez également ne pas vouloir utiliser une bibliothèque distincte à cette fin.Voici une autre approche qui est pure java et ne dépend pas du système de fichiers.
Java 8 n'est pas indispensable . Vous pouvez utiliser des boucles au lieu de flux. Et vous pouvez le tester comme ça
la source
ToolProvider.getSystemJavaCompiler()
, ce code n'analyse pas les packages imbriqués.Si vous n'utilisez aucun chargeur de classe dynamique, vous pouvez rechercher le chemin de classe et pour chaque entrée, recherchez le répertoire ou le fichier JAR.
la source
À noter
Si vous souhaitez avoir une liste de toutes les classes sous un package, vous pouvez utiliser
Reflection
la manière suivante:Cela créera une liste de classes que vous pourrez ensuite utiliser comme vous le souhaitez.
la source
C'est très possible, mais sans bibliothèques supplémentaires comme
Reflections
c'est difficile ...C'est difficile parce que vous n'avez pas d'instrument complet pour obtenir le nom de la classe.
Et, je prends le code de ma
ClassFinder
classe:la source
Sur la base de la réponse de @ Staale , et dans une tentative de ne pas compter sur des bibliothèques tierces, j'implémenterais l'approche du système de fichiers en inspectant l'emplacement physique du premier package avec:
la source
Si vous cherchez simplement à charger un groupe de classes connexes, Spring peut vous aider.
Spring peut instancier une liste ou une carte de toutes les classes qui implémentent une interface donnée dans une seule ligne de code. La liste ou la carte contiendra des instances de toutes les classes qui implémentent cette interface.
Cela étant dit, au lieu de charger la liste des classes hors du système de fichiers, implémentez simplement la même interface dans toutes les classes que vous souhaitez charger, quel que soit le package et utilisez Spring pour vous fournir des instances de toutes. De cette façon, vous pouvez charger (et instancier) toutes les classes que vous désirez, quel que soit le package dans lequel elles se trouvent.
D'un autre côté, si vous les avez tous dans un package, c'est ce que vous voulez, alors demandez simplement à toutes les classes de ce package d'implémenter une interface donnée.
la source
Java simple: FindAllClassesUsingPlainJavaReflectionTest.java
PS: pour simplifier les passe-partout pour la gestion des erreurs, etc., j'utilise ici
vavr
et leslombok
bibliothèquesd'autres implémentations peuvent être trouvées dans mon référentiel GitHub daggerok / java-réflexion-find-annotated-classes-or-methods
la source
Je n'ai pas pu trouver un court travail découpé pour quelque chose d'aussi simple. Alors voilà, je l'ai fait moi-même après avoir vissé pendant un moment:
la source
Si vous êtes au printemps, vous pouvez utiliser
PathMatchingResourcePatternResolver
;la source
Ce n'est pas possible, car toutes les classes du package peuvent ne pas être chargées, alors que vous connaissez toujours le package d'une classe.
la source