2012-06-13 4 views
49

Próbuję utworzyć narzędzie Java, które przeskanuje strukturę aplikacji Java i udostępni pewne istotne informacje. Aby to zrobić, muszę móc przeskanować wszystkie pliki .class z lokalizacji projektu (JAR/WAR lub tylko folder) i użyć refleksji, aby przeczytać o ich metodach. To okazuje się prawie niemożliwe.Jak załadować klasy w czasie wykonywania z folderu lub pliku JAR?

Mogę znaleźć wiele rozwiązań opartych na URLClassloader, które pozwalają mi ładować określone klasy z katalogu/archiwum, ale żadne, które pozwolą mi ładować klasy bez żadnych informacji o nazwie klasy lub strukturze pakietu.

EDYCJA: Myślę, że źle to sformułowałem. Moim problemem nie jest to, że nie mogę uzyskać wszystkich plików klas, mogę to zrobić z rekursją itp. I zlokalizować je poprawnie. Mój problem polega na uzyskaniu obiektu klasy dla każdego pliku klasy.

+1

Jak wczytać klasę ignorując jej pełną nazwę? Nie sądzę, że to możliwe. –

+4

Poniższe odpowiedzi pozwolą Ci zlokalizować pliki klas, ale w zależności od rozmiaru twojego projektu warto użyć [asm] (http://asm.ow2.org/) lub [javassist] (http: // www.csg.ci.iu-tokyo.ac.jp/~chiba/javassist/). Pozwoli to ci analizować klasy bez ładowania ich wszystkich do pamięci. –

Odpowiedz

87

Poniższy kod ładuje wszystkie klasy z pliku JAR. Nie musi nic wiedzieć o zajęciach. Nazwy klas są wyodrębniane z 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); 

} 

edit:

Jak sugerowano w komentarzach powyżej, byłoby javassist być również taka możliwość. inicjująca ClassPool gdzieś przed pętli while tworzyć powyższy kod i zamiast ładowania klasy z klasy loader, można utworzyć obiekt CtClass:

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

Z ctClass, można uzyskać wszystkie metody, pola zajęcia zagnieżdżone, .... Spójrz na javassist API: https://jboss-javassist.github.io/javassist/html/index.html

+1

Przepraszam, że przywołuję stary wpis (dziękuję za tę odpowiedź, działa dla mnie). Jednak 'nowy adres URL (" jar: file: "+ pathToJar +"!/")' Spowodował 'ClassNotFoundException'. Dla mnie zadziałało: 'URL [] urls = {new URL (" jar: "+ pathToJar +"!/")};' Nie wiesz dlaczego? Mam nadzieję, że pomaga komuś innemu. – taylorcressy

+0

Nice. Może chcesz zamknąć plik jarFile? spróbuj {...} wreszcie {jarFile.close(); } –

+0

Link nie działa. –

6

aby to zrobić, trzeba być w stanie skanować wszystkie pliki .class od lokalizacji projektu (JAR/WAR lub po prostu folder)

Skanowanie wszystkich plików w folderze jest proste. Jedną z opcji jest wywołanie File.listFiles() na File, która oznacza folder, a następnie iterowanie wynikowej tablicy. Aby przechodzić przez drzewa folderów zagnieżdżonych, użyj rekurencji.

Skanowanie plików pliku JAR można wykonać przy użyciu interfejsu API JarFile ... i nie trzeba powtarzać, aby przechodzić zagnieżdżone "foldery".

Żadne z nich nie jest szczególnie skomplikowane. Po prostu przeczytaj javadoc i rozpocznij kodowanie.

8

Lista Wszystkie klasy w pliku 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; 
} 
Powiązane problemy