2012-02-16 28 views
9

Tôi cần đếm số lượng các lớp, giao diện và enums được biên dịch trong một tệp jar được lập trình (vì vậy tôi cần ba số riêng biệt). API nào sẽ giúp tôi? (Tôi không thể sử dụng thư viện của bên thứ ba.)phân tích tệp jar theo lập trình

Tôi đã thử lược đồ khá phức tạp mà dường như không phải lúc nào cũng chính xác. Cụ thể, tôi đọc từng ZipEntry thành một byte [] và sau đó nạp kết quả vào trình nạp lớp tùy chỉnh của tôi, mở rộng CalssLoader chuẩn và gửi byte này [] tới lớp ClassLoader.defineClass (bảo vệ và không thể gọi trực tiếp từ mã ứng dụng)). Mã đầy đủ là on the Pastebin.

+0

Bạn có thể gọi 'ZipEntry.getName() 'và xem đó có phải là tệp' .class' không? Hay bạn cần phải đếm riêng các lớp và giao diện (và enums?)? – DNA

+0

Tôi cần đếm chúng một cách riêng biệt (ngoài ra nó được biết rằng không phải tất cả các tệp .class đều chứa đúng mã byte). –

+0

Các tệp .class có mã byte không chính xác mà chúng tôi muốn không tính. –

Trả lời

10

Tệp jar là tệp zip có mẫu cụ thể. Bạn có thể sử dụng một ZipFile và một ZipEntry hoặc các lớp con của họ JarFile và JarEntry.

Mã này (một phương thức của trình nạp lớp tùy chỉnh) sẽ trả về Bản đồ với các mảng của từng loại "lớp" mà bạn cần.

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

Cảm ơn rất nhiều, nó hoạt động gần như hoàn hảo. Một số chi tiết nhỏ: để có thể sử dụng 'super.addURL', bạn nên mở rộng' URLClassLoader' không chỉ 'Lớp tải '. Và sau đó bạn phải định nghĩa hàm tạo gọi 'super' với mảng url. Tôi ước tôi có thể nuôi nó bằng không, nhưng có một ngoại lệ. Vì vậy, tôi đã xây dựng một mảng với một URL tương ứng với jar của tôi. –

+1

Bạn có thể vượt qua một mảng trống ... Điều này hoạt động tốt ... Xin lỗi về những hiểu lầm về lớp siêu, đây là một UrlClassloader ... – Eldius

Các vấn đề liên quan