如何在运行时从文件夹或JAR加载类?
我正在尝试制作一个Java工具,它将扫描Java应用程序的结构并提供一些有意义的信息。 要做到这一点,我需要能够从项目位置(JAR / WAR或者只是一个文件夹)中扫描所有.class文件,并使用reflection来读取它们的方法。 这certificate是几乎不可能的。
我可以find很多基于URLClassloader的解决scheme,这些解决scheme允许我从一个目录/归档中加载特定的类,但是没有一个能够让我在没有关于类名或者包结构的任何信息的情况下加载类。
编辑:我觉得我措辞不好。 我的问题不是我不能得到所有的类文件,我可以用recursion等来做到这一点,并正确地find它们。 我的问题是获取每个类文件的Class对象。
以下代码从JAR文件加载所有类。 它不需要知道任何关于类。 类的名字是从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); }
编辑:
正如在上面的评论中所build议的那样,javassist也是一种可能性。 在while循环形成上面的代码之前,在某个地方初始化一个ClassPool,而不是使用类加载器加载类,您可以创build一个CtClass对象:
ClassPool cp = ClassPool.getDefault(); ... CtClass ctClass = cp.get(className);
从ctClass,你可以得到所有的方法,字段,嵌套类,….看看javassist api: https : //jboss-javassist.github.io/javassist/html/index.html
列出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; }
要做到这一点,我需要能够从项目位置(JAR / WAR或只是一个文件夹)扫描所有的.class文件,
扫描文件夹中的所有文件都很简单。 一个选项是调用表示该文件夹的File
File.listFiles()
,然后迭代结果数组。 要遍历嵌套文件夹的树,请使用recursion。
扫描JAR文件的文件可以使用JarFile
API来完成,而且不需要recursion来遍历嵌套的“文件夹”。
这些都不是特别复杂。 只要阅读javadoc并开始编码。