Search code examples
bytecodejava-bytecode-asm

How to use ASM Opcodes.ACC_SYNTHETIC


I am testing ACC_SYNTHETIC on a method by using ASM. The follows is my code

    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$1", "()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);

    }

But the result class file has nothing.

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

package cn.curious.asm;

public class Bean {
}

I feel confusion about ACC_SYNTHETIC, how to use it correctly?


Update
Here is the javap output. The -p make it work.

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$1
  #6 = Utf8               ()V
  #7 = Utf8               Code
{
  private static void lambda$main$1();
    descriptor: ()V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=0, locals=0, args_size=0
         0: return
}


Solution

  • Thats the idea behind synthetic methods, these are methods generated by compiler, so decompilers often skip it by default, as by definition they should not be needed in source code.

    Like java specification states that

    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).

    And jvm one:

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

    Try to use javap -verbose -private -s -classpath yourJar.jar my.Class (or just directly to class filed) instead, it should list all your methods. Or just generate second normal method that will invoke this synthetic method and check if you can run it. Or just use reflections and getDeclaredMethods method to get all declared methods, including synthetic ones.