Java注释的默认值是否已编译为字节码?

时间:2015-10-07 14:31:45

标签: java annotations java-8 bytecode

我尝试为Java字节码实现几个静态分析。他们试图计算某种方法是否具有特定属性,例如是一种工厂方法。因为这些分析很难测试,所以我决定编写一些Java代码并使用正确的属性直接注释方法。运行分析后,很容易自动检查计算属性和带注释的属性是否相同。

MyAnnotation:

@Retention(RUNTIME)
@Target(METHOD)
public @interface FactoryMethodProperty {

    FactoryMethodKeys value() default FactoryMethodKeys.NonFactoryMethod;
}

示例测试代码:

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();
    }
}

因为我的测试代码中的大多数方法都不是工厂方法,所以我将默认设置为枚举值“FactoryMethodKeys.NonFactoryMethod”。但是,当我没有将枚举值显式传递给注释时,它不会被编译为字节码。

字节码:

 #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, locals=0, 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
}

我错了什么?为什么完全忽略默认值?

2 个答案:

答案 0 :(得分:9)

它不需要在那里。在运行时,JVM构造可以检索的注释实例。此实例将使用Child2值进行初始化,该值位于注释本身的Child1文件中。这表示为AnnotationDefault attribute

  

Child2属性是一个可变长度属性   某些dscmd3.Fill(dsS); 结构的属性表(§4.6),即   那些代表注释类型的元素。的default   属性记录由...表示的元素的默认值   .class结构。

     

每个AnnotationDefault结构表示注释的元素   类型最多只能包含一个method_info属性。 Java   虚拟机必须使此默认值可用,因此它可以   通过适当的反思API应用

您最终将调用注释实例的AnnotationDefault方法(或您定义的任何其他方法),它将返回该值。

答案 1 :(得分:4)

如果您查看注释的字节码,您将在那里看到默认值。使用'TestContorller', function($scope, $window)并修剪不相关的内容:

$window.alert('action handler called')