2012-02-16 66 views
9

我需要以編程方式計算給定jar文件中已編譯的類,接口和枚舉的數量(所以我需要三個單獨的數字)。哪個API可以幫助我? (我不能使用第三方庫。)以編程方式分析jar文件

我已經嘗試了相當棘手的方案,這似乎並不總是正確的。也就是說,我將每個ZipEntry讀入一個byte [],然後將結果提供給我的自定義類加載器,該加載器擴展了標準CalssLoader,並將此byte []發送給ClassLoader.defineClass(這是保護,不能直接從應用程序代碼調用) )。完整的代碼是on the Pastebin

+0

你可以調用'ZipEntry.getName()'看看它是否是'.class'文件嗎?或者你需要分別計算類和接口(和枚舉?)? – DNA 2012-02-16 16:21:48

+0

我需要分別對它們進行計數(另外還知道並非所有.class文件都包含正確的字節碼)。 – 2012-02-16 16:30:51

+0

我們不希望計算帶有錯誤字節碼的.class文件。 – 2012-02-16 16:37:33

回答

10

jar文件是一個具有特定模式的zip文件。 您可以使用ZipFile和ZipEntry或其子類JarFile和JarEntry。

這段代碼(自定義類加載器的一個方法)將返回一個包含您需要的每個「類」類型的數組的Map。

public Map<String, List<Class<?>>> loadAndScanJar(File jarFile) 
     throws ClassNotFoundException, ZipException, IOException { 

    // Load the jar file into the JVM 
    // You can remove this if the jar file already loaded. 
    super.addURL(jarFile.toURI().toURL()); 

    Map<String, List<Class<?>>> classes = new HashMap<String, List<Class<?>>>(); 

    List<Class<?>> interfaces = new ArrayList<Class<?>>(); 
    List<Class<?>> clazzes = new ArrayList<Class<?>>(); 
    List<Class<?>> enums = new ArrayList<Class<?>>(); 
    List<Class<?>> annotations = new ArrayList<Class<?>>(); 

    classes.put("interfaces", interfaces); 
    classes.put("classes", clazzes); 
    classes.put("annotations", annotations); 
    classes.put("enums", enums); 

    // Count the classes loaded 
    int count = 0; 

    // Your jar file 
    JarFile jar = new JarFile(jarFile); 
    // Getting the files into the jar 
    Enumeration<? extends JarEntry> enumeration = jar.entries(); 

    // Iterates into the files in the jar file 
    while (enumeration.hasMoreElements()) { 
     ZipEntry zipEntry = enumeration.nextElement(); 

     // Is this a class? 
     if (zipEntry.getName().endsWith(".class")) { 

      // Relative path of file into the jar. 
      String className = zipEntry.getName(); 

      // Complete class name 
      className = className.replace(".class", "").replace("/", "."); 
      // Load class definition from JVM 
      Class<?> clazz = this.loadClass(className); 

      try { 
       // Verify the type of the "class" 
       if (clazz.isInterface()) { 
        interfaces.add(clazz); 
       } else if (clazz.isAnnotation()) { 
        annotations.add(clazz); 
       } else if (clazz.isEnum()) { 
        enums.add(clazz); 
       } else { 
        clazzes.add(clazz); 
       } 

       count++; 
      } catch (ClassCastException e) { 

      } 
     } 
    } 

    System.out.println("Total: " + count); 

    return classes; 
} 
+0

非常感謝,它幾乎完美地工作。一些小的細節:爲了能夠使用'super.addURL',你應該擴展'URLClassLoader'而不僅僅是'ClassLoader'。然後你必須定義一個構造函數,這個構造函數用urls數組來調用'super'。我希望我可以餵它與null,但有一個例外。所以我構建了一個與我的jar對應的URL。 – 2012-02-16 18:01:06

+1

你可以傳遞一個空數組...這工作正常...對超級類的誤解抱歉,這是一個UrlClassloader ... – Eldius 2012-02-17 00:52:35