2015-10-07 13 views
10

私はJavaバイトコードのいくつかの静的解析を実装しようとしています。特定のメソッドが特定のプロパティを持っているかどうかを計算しようとします。ファクトリメソッドです。これらの分析はテストが難しいため、私はいくつかの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にデフォルトを設定"しかし、enum値をアノテーションに明示的に渡さないと、バイトコードにコンパイルされません。

バイトコード:私は間違っていた何

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

?デフォルト値は完全に無視されるのはなぜですか?

答えて

8

そこにいる必要はありません。実行時に、JVMは取得可能なアノテーションインスタンスを作成します。このインスタンスは、defaultの値で初期化されます。この値は、アノテーション自体のファイル.classにあります。それはAnnotationDefault attribute

AnnotationDefault属性として表されるのは、注釈型の要素を表す特定のmethod_info構造(§4.6)、すなわち それらの 属性テーブルの可変長属性です。 AnnotationDefault 属性は、 method_info構造体で表される要素の既定値を記録します。

タイプの要素を表す各構造は、最大でAnnotationDefaultという1つの属性を含むことができます。 Java 仮想マシンでは、このデフォルト値を利用できるようにして、 を適切な反映APIで適用できるようにする必要があります。

最後に、注釈インスタンスのvalue()メソッド(または定義した他のメソッド)を呼び出すと、その値が返されます。

4

注釈のバイトコードを調べると、そこにデフォルトが表示されます。 javap -c -vを使用して、無関係なものを切り捨てる:

... 
ConstantPool: 
    #7 = Utf8    LFactoryMethodKeys 
    #8 = Utf8    NonFactoryMethod 
... 
{ 
    public abstract FactoryMethodKeys value(); 
    flags: ACC_PUBLIC, ACC_ABSTRACT 
    AnnotationDefault: 
     default_value: e#7.#8} 
関連する問題