如何使用 ASM Opcodes.ACC_SYNTHETIC

How to use ASM Opcodes.ACC_SYNTHETIC

我正在使用 ASM 测试 ACC_SYNTHETIC 方法。以下是我的代码

    public static void generateMethodBean() throws IOException {
        System.out.println("11111");
        ClassWriter cw = new ClassWriter(0);
        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "cn/curious/asm/Bean", null, "java/lang/Object", null);

        MethodVisitor m0Visitor = cw.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, "lambda$main", "()V", null, null);
        m0Visitor.visitCode();
        m0Visitor.visitInsn(Opcodes.RETURN);
        m0Visitor.visitMaxs(0, 0);
        m0Visitor.visitEnd();

        cw.visitEnd();
        byte[] buffer = cw.toByteArray();
//        StringWriter stringWriter = new StringWriter();
//        PrintWriter printWriter = new PrintWriter(stringWriter);
//        CheckClassAdapter.verify(new ClassReader(buffer), true, printWriter);
//        System.out.println(printWriter.toString());

        File file = new File(FILE_PATH_PREFIX + File.separator + "Bean2.class");
        FileUtils.writeByteArrayToFile(file, buffer);

    }

但是结果class文件什么都没有。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package cn.curious.asm;

public class Bean {
}

我对ACC_SYNTHETIC感到困惑,如何正确使用它?


更新
这是 javap 输出。 -p 让它工作。

javap -v -l -s -p Bean.class 

Classfile /Users/Documents/work/idea_workspace/asmtest/src/main/java/cn/curious/asm/Bean.class
  Last modified 2020-3-5; size 127 bytes
  MD5 checksum 7367bcf65d9a32a72e4261101d3697cc
public class cn.curious.asm.Bean
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC
Constant pool:
  #1 = Utf8               cn/curious/asm/Bean
  #2 = Class              #1              // cn/curious/asm/Bean
  #3 = Utf8               java/lang/Object
  #4 = Class              #3              // java/lang/Object
  #5 = Utf8               lambda$main
  #6 = Utf8               ()V
  #7 = Utf8               Code
{
  private static void lambda$main();
    descriptor: ()V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=0, locals=0, args_size=0
         0: return
}

这就是合成方法背后的想法,这些是编译器生成的方法,因此反编译器通常默认跳过它,因为根据定义,源代码中不需要它们。

喜欢java 规范指出

  1. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).

和 jvm 之一:

The ACC_SYNTHETIC flag indicates that this method was generated by a compiler and does not appear in source code [with some exceptions]

尝试使用 javap -verbose -private -s -classpath yourJar.jar my.Class(或直接向 class 提交),它应该会列出您所有的方法。或者只是生成第二个普通方法来调用这个合成方法并检查你是否可以 运行 它。或者只使用反射和 getDeclaredMethods 方法来获取所有声明的方法,包括合成方法。