【问题标题】:analyze jar file programmatically以编程方式分析 jar 文件
【发布时间】:2012-03-08 01:02:47
【问题描述】:

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

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

【问题讨论】:

  • 你能打电话给ZipEntry.getName()看看是不是.class文件吗?还是需要分别统计类和接口(以及枚举?)?
  • 我需要单独计算它们(此外众所周知,并非所有的 .class 文件都包含正确的字节码)。
  • 我们希望不计算字节码不正确的 .class 文件。
  • 在这种情况下,您现有的方法在这种情况下看起来不错 - 但在哪些情况下它无法正常工作?
  • 我在 Apache commons-io.jar 上尝试过(直接链接:mmcs.sfedu.ru/~ulysses/Misc/commons-io.jar)那里有 76 个 .class 文件,但我的代码输出 47 2 0(类接口枚举)。

标签: java jar classloader


【解决方案1】:

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;
}

【讨论】:

  • 非常感谢,它几乎可以完美运行。一些小细节:为了能够使用super.addURL,您应该扩展URLClassLoader 而不仅仅是ClassLoader。然后您必须定义构造函数,该构造函数使用 url 数组调用 super。我希望我可以用 null 喂它,但有一个例外。所以我构建了一个数组,其中包含一个对应于我的 jar 的 URL。
  • 您可以传递一个空数组...这很好...抱歉对超类的误解,这是一个 UrlClassloader...
猜你喜欢
  • 2010-12-15
  • 2012-06-23
  • 1970-01-01
  • 2018-01-07
  • 2020-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-01
相关资源
最近更新 更多