2012-02-16 10 views
9

Ho bisogno di contare il numero di classi, interfacce ed enumerazioni compilate in un dato file jar a livello di codice (quindi ho bisogno di tre numeri separati). Quale API mi può aiutare? (Non posso usare librerie di terze parti.)analizza il file jar a livello di programmazione

Ho già provato uno schema piuttosto complicato che sembra non sempre corretto. Vale a dire, leggo ogni ZipEntry in un byte [] e poi li trasmetto al mio caricatore di classi personalizzato che estende CalssLoader standard e invia questo byte [] a ClassLoader.defineClass (che è protetto e non può essere chiamato direttamente dal codice dell'applicazione)). Il codice completo è on the Pastebin.

+0

Si può chiamare 'ZipEntry.getName()' e vedere se si tratta di un file '.class'? O hai bisogno di contare separatamente le classi e le interfacce (e le enumerazioni?)? – DNA

+0

Devo contarli separatamente (inoltre è noto che non tutti i file .class contengono il codice byte corretto). –

+0

I file .class con codice byte errato non vengono conteggiati. –

risposta

10

Un file jar è un file zip con un motivo specifico. È possibile utilizzare un file ZipFile e uno ZipEntry o le loro classi figlio JarFile e JarEntry.

Questo codice (un metodo di un classloader personalizzato) restituirà una mappa con matrici di ogni tipo di "classe" di cui hai bisogno.

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

Grazie mille, funziona quasi perfettamente. Alcuni dettagli minori: per poter usare 'super.addURL' devi estendere' URLClassLoader' non solo a 'ClassLoader'. E poi devi definire il costruttore che chiama 'super' con la matrice di URL. Vorrei poterlo alimentare con null, ma ho ottenuto un'eccezione. Così ho costruito un array con un URL che corrisponde al mio barattolo. –

+1

Si può passare un array vuoto ... Funziona bene ... Scusa per il frainteso della super classe, questo è un UrlClassloader ... – Eldius

Problemi correlati