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