Java 以编程方式分析jar文件

Java 以编程方式分析jar文件,java,jar,classloader,Java,Jar,Classloader,我需要以编程方式计算给定jar文件中已编译类、接口和枚举的数量(因此我需要三个单独的数字)。哪种API可以帮助我?(我不能使用第三方库。) 我已经尝试过相当棘手的方案,似乎并不总是正确的。也就是说,我将每个ZipEntry读入一个字节[],然后将结果提供给我的自定义类加载器,该类加载器扩展了标准的CalssLoader,只将这个字节[]发送给ClassLoader.defineClass(它是受保护的,不能直接从应用程序代码中调用)。完整代码是。jar文件是具有特定模式的zip文件。 您可以使用

我需要以编程方式计算给定jar文件中已编译类、接口和枚举的数量(因此我需要三个单独的数字)。哪种API可以帮助我?(我不能使用第三方库。)


我已经尝试过相当棘手的方案,似乎并不总是正确的。也就是说,我将每个ZipEntry读入一个字节[],然后将结果提供给我的自定义类加载器,该类加载器扩展了标准的CalssLoader,只将这个字节[]发送给ClassLoader.defineClass(它是受保护的,不能直接从应用程序代码中调用)。完整代码是。

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;
}
public-Map>>classes=new-HashMap>interfaces=new-ArrayList>clazzes=new-ArrayList>enums=new-ArrayList>annotations=new-ArrayList-clazz=this.loadClass(className);
试一试{
//验证“类”的类型
if(clazz.isInterface()){
接口。添加(clazz);
}else if(clazz.isAnnotation()){
添加注释(clazz);
}else if(clazz.isEnum()){
enums.add(clazz);
}否则{
添加(clazz);
}
计数++;
}catch(ClassCastException e){
}
}
}
系统输出打印项次(“总计:+计数);
返回类;
}

你能调用
ZipEntry.getName()
看看它是不是一个
.class
文件吗?或者您需要单独计算类和接口(以及枚举?)吗?我需要单独计算它们(另外,我们知道并非所有的.class文件都包含正确的字节码)。我们不希望计算具有错误字节码的.class文件。在这种情况下,在这种情况下,您现有的方法看起来不错-但在什么情况下它不能正常工作?我在Apache commons-io.jar(直接链接:)上尝试了它。那里有76个.class文件,但我的代码输出47 2 0(类接口枚举)。非常感谢,它工作得几乎完美。一些小细节:为了能够使用
super.addURL
,您应该扩展
URLClassLoader
,而不仅仅是
ClassLoader
。然后,您必须定义构造函数,该构造函数使用URL数组调用
super
。我希望我能给它输入null,但得到了一个异常。所以我用一个URL构建了一个数组,它对应于我的jar。。。这个很好用。。。很抱歉,对超类的误解,这是一个UrlClassloader。。。