Как загружать классы во время выполнения из папки или JAR?
Я пытаюсь создать инструмент Java, который сканирует структуру приложения Java и предоставит некоторую значимую информацию. Для этого мне нужно иметь возможность сканировать все файлы .class из местоположения проекта (JAR/WAR или только папку) и использовать рефлексию для чтения своих методов. Это оказывается почти невозможным.
Я могу найти множество решений на основе URLClassloader, которые позволяют загружать определенные классы из каталога/архива, но ни один из них не позволит мне загружать классы без какой-либо информации о имени класса или структуре пакета.
EDIT:
Я думаю, что я сформулировал это плохо. Моя проблема не в том, что я не могу получить все файлы классов, я могу сделать это с рекурсией и т.д. И найти их правильно. Моя проблема - получить объект Class для каждого файла класса.
Ответы
Ответ 1
Следующий код загружает все классы из 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);
}
изменить:
Как было предложено в комментариях выше, джавассист также будет возможностью.
Инициализируйте ClassPool где-то до цикла while, сформировав код выше, и вместо загрузки класса с загрузчиком класса вы можете создать объект CtClass:
ClassPool cp = ClassPool.getDefault();
...
CtClass ctClass = cp.get(className);
Из ctClass вы можете получить все методы, поля, вложенные классы,....
Взгляните на javassist api:
https://jboss-javassist.github.io/javassist/html/index.html
Ответ 2
Список всех классов внутри файла 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;
}
Ответ 3
Для этого мне нужно иметь возможность сканировать все файлы .class из местоположения проекта (JAR/WAR или только папка)
Сканирование всех файлов в папке прост. Один из вариантов заключается в вызове File.listFiles()
в File
, который обозначает папку, а затем итерации результирующего массива. Чтобы перемещаться по деревьям вложенных папок, используйте рекурсию.
Сканирование файлов JAR файла можно выполнить с помощью API JarFile
... и вам не нужно рекурсивно проходить через вложенные "папки".
Ни один из них не является особенно сложным. Просто прочитайте javadoc и начните кодирование.