Are the default values of Java annotations compiled into bytecode?
I tried to implement several static analyses for Java bytecode They try to calculate whether a method has specific properties, such as a factory method Because these analyses are difficult to test, I decided to write some java code and annotate the methods directly with the correct attributes After running the analysis, it is easy to automatically check whether the calculated and annotated properties are the same
MyAnnotation:
@Retention(RUNTIME) @Target(METHOD) public @interface FactoryMethodProperty { FactoryMethodKeys value() default FactoryMethodKeys.NonFactoryMethod; }
Sample test code:
public class PublicFactoryMethod { private PublicFactoryMethod(){ // I'm private } @FactoryMethodProperty public static void newInstanceAfterOtherConstructorCall(){ new TransFacoryMethod(); new PublicFactoryMethod(); } @FactoryMethodProperty(FactoryMethodKeys.IsFactoryMethod) public static PublicFactoryMethod newInstance(){ return new PublicFactoryMethod(); } }
Because most of the methods in my test code are not factory methods, I set the default value to the enumeration value "factorymethodkeys. Nonfactory method" However, when I do not explicitly pass the enumeration value to the annotation, it will not be compiled into bytecode
Bytecode:
#23 = Utf8 value #24 = Utf8 Lorg/opalj/fpa/test/annotations/FactoryMethodKeys; #25 = Utf8 IsFactoryMethod { public static void newInstanceAfterOtherConstructorCall(); descriptor: ()V flags: ACC_PUBLIC,ACC_STATIC RuntimeVisibleAnnotations: 0: #16() Code: stack=1,locals=0,args_size=0 0: new #17 // class factoryMethodTest/TransFacoryMethod 3: invokespecial #19 // Method factoryMethodTest/TransFacoryMethod."<init>":()V 6: new #1 // class factoryMethodTest/PublicFactoryMethod 9: invokespecial #20 // Method "<init>":()V 12: return LineNumberTable: line 49: 0 line 50: 6 line 51: 12 LocalVariableTable: Start Length Slot Name Signature public static factoryMethodTest.PublicFactoryMethod newInstance(); descriptor: ()LfactoryMethodTest/PublicFactoryMethod; flags: ACC_PUBLIC,ACC_STATIC RuntimeVisibleAnnotations: 0: #16(#23=e#24.#25) Code: stack=2,args_size=0 0: new #1 // class factoryMethodTest/PublicFactoryMethod 3: dup 4: invokespecial #20 // Method "<init>":()V 7: areturn LineNumberTable: line 55: 0 LocalVariableTable: Start Length Slot Name Signature }
What did I do wrong? Why is the default completely ignored?
Solution
It does not need to be there at runtime, and the JVM constructs a retrievable annotation instance The instance will be initialized with the default value, which is in Class file, used to comment itself This is represented as annotationdefault attribute
You will eventually call the value () method of the annotation instance (or any other method you define) and return the value