web-dev-qa-db-fra.com

Comment charger des classes au moment de l'exécution à partir d'un dossier ou d'un fichier JAR?

J'essaie de créer un outil Java) qui analysera la structure d'une application Java et fournira des informations utiles. Pour ce faire, je dois pouvoir pour analyser tous les fichiers .class à partir de l’emplacement du projet (JAR/WAR ou tout simplement un dossier) et utiliser la réflexion pour en savoir plus sur leurs méthodes.

Je peux trouver beaucoup de solutions basées sur URLClassloader qui me permettent de charger des classes spécifiques à partir d'un répertoire/archive, mais aucune ne me permet de charger des classes sans avoir aucune information sur le nom de la classe ou la structure du paquet.

EDIT: Je pense que j'ai mal formulé cela. Mon problème n'est pas que je ne peux pas obtenir tous les fichiers de classe, je peux le faire avec la récursivité, etc. et les localiser correctement. Mon problème est d'obtenir un objet de classe pour chaque fichier de classe.

57
Sam Stern

Le code suivant charge toutes les classes à partir d'un fichier JAR. Il n'a pas besoin de savoir quoi que ce soit sur les cours. Les noms des classes sont extraits de JarEntry.

JarFile jarFile = new JarFile(pathToJar);
Enumeration<JarEntry> e = jarFile.entries();

URL[] urls = { new URL("jar:file:" + pathToJar+"!/") };
URLClassLoader cl = URLClassLoader.newInstance(urls);

while (e.hasMoreElements()) {
    JarEntry je = e.nextElement();
    if(je.isDirectory() || !je.getName().endsWith(".class")){
        continue;
    }
    // -6 because of .class
    String className = je.getName().substring(0,je.getName().length()-6);
    className = className.replace('/', '.');
    Class c = cl.loadClass(className);

}

modifier:

Comme suggéré dans les commentaires ci-dessus, javassist serait également une possibilité. Initialisez un ClassPool quelque part avant la boucle while du code ci-dessus et au lieu de charger la classe avec le chargeur de classes, vous pouvez créer un objet CtClass:

ClassPool cp = ClassPool.getDefault();
...
CtClass ctClass = cp.get(className);

À partir de ctClass, vous pouvez obtenir toutes les méthodes, champs, classes imbriquées, .... Consultez l'API javassist: https://jboss-javassist.github.io/javassist/html/index.html

99
Apfelsaft

Répertorie toutes les classes dans le fichier jar.

public static List getClasseNames(String jarName) {
    ArrayList classes = new ArrayList();

    if (debug)
        System.out.println("Jar " + jarName );
    try {
        JarInputStream jarFile = new JarInputStream(new FileInputStream(
                jarName));
        JarEntry jarEntry;

        while (true) {
            jarEntry = jarFile.getNextJarEntry();
            if (jarEntry == null) {
                break;
            }
            if (jarEntry.getName().endsWith(".class")) {
                if (debug)
                    System.out.println("Found "
                            + jarEntry.getName().replaceAll("/", "\\."));
                classes.add(jarEntry.getName().replaceAll("/", "\\."));
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return classes;
}
9
amicngh

Pour ce faire, je dois pouvoir analyser tous les fichiers .class à partir de l’emplacement du projet (JAR/WAR ou simplement un dossier).

L'analyse de tous les fichiers d'un dossier est simple. Une option consiste à appeler File.listFiles() sur le File qui désigne le dossier, puis itérer le tableau résultant. Pour parcourir les arborescences des dossiers imbriqués, utilisez la récursivité.

L'analyse des fichiers d'un fichier JAR peut être effectuée à l'aide de l'API JarFile ... et vous n'avez pas besoin de recurse pour parcourir les "dossiers" imbriqués.

Ni l'un ni l'autre n'est particulièrement compliqué. Il suffit de lire le javadoc et de commencer à coder.

6
Stephen C