2012-06-13 2 views
49

Я пытаюсь создать инструмент Java, который сканирует структуру приложения Java и предоставит значимую информацию. Для этого мне нужно иметь возможность сканировать все файлы .class из местоположения проекта (JAR/WAR или только папку) и использовать рефлексию для чтения своих методов. Это оказывается почти невозможным.Как загрузить классы во время выполнения из папки или JAR?

Я могу найти множество решений на основе URLClassloader, которые позволяют загружать определенные классы из каталога/архива, но ни один из них не позволит мне загружать классы без какой-либо информации о имени класса или структуре пакета.

EDIT: Я думаю, что я сформулировал это плохо. Моя проблема не в том, что я не могу получить все файлы классов, я могу сделать это с рекурсией и т. Д. И найти их правильно. Моя проблема - получить объект Class для каждого файла класса.

+1

Как вы можете загрузить класс, игнорирующий его полное имя? Я не думаю, что это возможно. –

+4

Ответы ниже помогут вам найти файлы классов, но, в зависимости от размера вашего проекта, возможно, стоит использовать [asm] (http://asm.ow2.org/) или [javassist] (http: // www.csg.ci.iu-tokyo.ac.jp/~chiba/javassist/). Это позволит вам анализировать классы, не загружая их все в память. –

ответ

87

Следующий код загружает все классы из 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); 

} 

редактировать:

Как было отмечено в комментариях выше, Javassist также будет возможность. Инициализировать ClassPool где-то раньше время цикла образуют код, указанный выше, и вместо загрузки класса с загрузчиком класса, можно создать объект CtClass:

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

С ctClass, вы можете получить все методы, поля , вложенные классы, .... Посмотрите на Javassist API: https://jboss-javassist.github.io/javassist/html/index.html

+1

Жаль воспитывать старое сообщение (спасибо за этот ответ, это работает для меня). Однако, новый URL ("jar: file:" + pathToJar + "! /") 'Вызвал' ClassNotFoundException'. Что для меня работало: 'URL [] urls = {новый URL (" jar: "+ pathToJar +"!/")};' Не знаете, почему? Надеюсь, это поможет кому-то другому. – taylorcressy

+0

Ницца. Возможно, вы захотите закрыть jarFile? try {...} finally {jarFile.close(); } –

+0

Ссылка мертва. –

6

чтобы сделать это, мне нужно, чтобы иметь возможность сканировать все файлы .class от расположения проекта (JAR/WAR или только папка)

Сканирование всех файлов в папке прост. Один из вариантов заключается в вызове File.listFiles() на File, который обозначает папку, а затем итерации результирующего массива. Чтобы перемещаться по деревьям вложенных папок, используйте рекурсию.

Сканирование файлов JAR-файла может быть выполнено с использованием API JarFile ... и вам не нужно рекурсивно отслеживать вложенные «папки».

Ни один из них не является особенно сложным. Просто прочитайте javadoc и начните кодирование.

8

Список Все классы внутри файла 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; 
} 
Смежные вопросы