2012-02-16 5 views
9

コンパイルされたクラス、インターフェイス、および列挙型の数を、プログラムで指定したJARファイルに入れる必要があります(3つの別々の番号が必要です)。どのAPIが私を助けますか? (私はサードパーティ製のライブラリを使用することはできません)jarファイルをプログラムで分析する

私はすでに、正しくはないようだがかなりトリッキーなスキームを試みました。つまり、各ZipEntryをバイト[]に読み込んだ後、標準のCalssLoaderを拡張したカスタムクラスローダーに結果を送り、このバイト[]をClassLoader.defineClassに送信します(これは保護されており、アプリケーションコードから直接呼び出すことはできませんでした)。完全なコードはon the Pastebinです。

+0

'ZipEntry.getName()'を呼び出して '.class'ファイルであるかどうか確認できますか?または、クラスとインタフェース(および列挙型)を別々に数える必要がありますか? – DNA

+0

私はそれらを別々に数える必要があります(さらに、すべての.classファイルが正しいバイトコードを含んでいるわけではないことが知られています)。 –

+0

カウントしたくない不正なバイトコードを持つ.class-files。 –

答えて

10

jarファイルは、特定のパターンを持つzipファイルです。 ZipFileとZipEntry、またはそれらの子クラスJarFileとJarEntryを使用できます。

このコード(カスタムクラスローダーのメソッド)は、必要な "クラス"の各タイプの配列を持つマップを返します。

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'を使用できるようにするには' ClassLoader'だけでなく 'URLClassLoader'を拡張する必要があります。そして、あなたはURLの配列で 'super'を呼び出すコンストラクタを定義しなければなりません。私はそれをヌルで食べればいいと思うが、例外がある。だから私は私の瓶に対応する1つのURLを持つ配列を構築しました。 –

+1

空の配列を渡す可能性があります...これはうまくいきます...スーパークラスについて誤解されて申し訳ありませんが、これはUrlClassloaderです... – Eldius

関連する問題