【问题标题】:ASM duplicate methodsASM 重复方法
【发布时间】:2018-10-02 12:17:47
【问题描述】:

我正在尝试删除所有 System#exit 调用,它似乎正在工作,但我最终得到了方法重复。

我的代码如下所示:

    JarInputStream jis = new JarInputStream(new FileInputStream(new File(input)));
    JarOutputStream jos = new JarOutputStream(new FileOutputStream(new File(output)));

    byte[] buffer = new byte[4096];

    JarEntry entry;

    while ((entry = jis.getNextJarEntry()) != null) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int size;

        while ((size = jis.read(buffer)) != -1) {
            bos.write(buffer, 0, size);
        }

        bos.close();

        jos.putNextEntry(new JarEntry(entry.getName()));

        if (entry.getName().endsWith(".class")) {
            ClassReader cr = new ClassReader(bos.toByteArray());
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

            ClassTransformer cm = new ClassTransformer(cw);

            ClassNode cn = new ClassNode();
            cr.accept(cn, 0);

            System.out.println("Analyzing bytecode in class " + cn.name);

            List<MethodNode> methods = cn.methods;

            for (MethodNode method : methods) {
                System.out.println("Analyzing bytecode in method " + method.name);

                String[] exceptions = (String[]) method.exceptions.toArray(new String[method.exceptions.size()]);

                cm.visitMethod(method.access, method.name, method.desc, method.signature, exceptions);
            }

            cr.accept(cm, ClassReader.EXPAND_FRAMES);
            jos.write(cw.toByteArray());
        } else {
            jos.write(bos.toByteArray());
        }
    }

    jos.close();
    jis.close();

ClassTransformer 和 MethodTransformer 都是自定义类。如果你想让我也提供它们,请告诉我。

【问题讨论】:

    标签: java-bytecode-asm


    【解决方案1】:

    您应该熟悉Visitor pattern

    声明

    cr.accept(cm, ClassReader.EXPAND_FRAMES);
    

    已经在完成全部工作。 ClassReader 将调用指定ClassTransformer 上的所有visit… 方法,当遵循此API 的标准编程模型时,这将对ClassWriter 进行所有必要的委托。

    换句话说,整个区块

    ClassNode cn = new ClassNode();
    cr.accept(cn, 0);
    
    System.out.println("Analyzing bytecode in class " + cn.name);
    
    List<MethodNode> methods = cn.methods;
    
    for (MethodNode method : methods) {
        System.out.println("Analyzing bytecode in method " + method.name);
    
        String[] exceptions = (String[]) method.exceptions.toArray(new String[method.exceptions.size()]);
    
        cm.visitMethod(method.access, method.name, method.desc, method.signature, exceptions);
    }
    

    已经过时了,因为它循环所有方法并为每个方法调用visitMethod,除了已经完成整个工作的语句,你得到每个方法两次也就不足为奇了。

    所以只需删除该代码块。

    嗯,当然,你可以保留打印语句……


    顺便说一句,您可以进一步简化代码,只需将JarInputStream 传递给ClassReader(InputStream) 构造函数,而无需先复制到ByteArrayOutputStream

    清理后的代码如下所示:

    try(JarInputStream jis = new JarInputStream(new FileInputStream(input));
        JarOutputStream jos = new JarOutputStream(new FileOutputStream(output)) ) {
    
        JarEntry entry;
        while((entry = jis.getNextJarEntry()) != null) {
            jos.putNextEntry(new JarEntry(entry.getName()));
    
            if (entry.getName().endsWith(".class")) {
                ClassReader cr = new ClassReader(jis);
                ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
                ClassTransformer cm = new ClassTransformer(cw);
                System.out.println("Analyzing bytecode in class " + cr.getClassName());
                cr.accept(cm, ClassReader.EXPAND_FRAMES);
                jos.write(cw.toByteArray());
            } else {
                jis.transferTo(jos); // Java 9
                /* before Java 9:
                byte[] buffer = new byte[8192];
                for(int read; (read = jis.read(buffer, 0, buffer.length)) >= 0; )
                    jos.write(buffer, 0, read);
                */
            }
        }
    }
    

    请注意,我还将ClassReader 传递给ClassWriter 的构造函数。对于这样的用例,只需进行少量更改,就可以优化代码生成。

    【讨论】:

      猜你喜欢
      • 2012-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-03
      • 1970-01-01
      • 2018-03-03
      相关资源
      最近更新 更多