2015-10-07 16 views
10

Provo ad implementare diverse analisi statiche per bytecode Java. Cercano di calcolare se un determinato metodo ha una proprietà specifica, ad es. è un metodo di fabbrica. Poiché queste analisi sono difficili da testare, ho deciso di scrivere del codice Java e di annotare i metodi direttamente con la proprietà corretta. Dopo aver eseguito l'analisi, è abbastanza semplice controllare automaticamente se la proprietà calcolata e quella annotata è la stessa.I valori predefiniti dell'annotazione Java vengono compilati in bytecode?

MyAnnotation:

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

    FactoryMethodKeys value() default FactoryMethodKeys.NonFactoryMethod; 
} 

codice di prova Esempio:

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

Poiché la maggior parte dei metodi nel mio codice di prova sono metodi di fabbrica, ho impostato il valore di default per il valore enum "FactoryMethodKeys.NonFactoryMethod ". Ma quando non passo esplicitamente il valore enum all'annotazione, non viene compilato nel 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, 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 
} 

cosa ho sbagliato? Perché il valore predefinito è completamente ignorato?

risposta

8

Non è necessario esserci. In fase di runtime, JVM crea un'istanza di annotazione che è possibile recuperare. Questa istanza verrà inizializzata con il valore default che si trova nel file .class per l'annotazione stessa. Questo è rappresentato come AnnotationDefault attribute

L'attributo AnnotationDefault è un attributo di lunghezza variabile nella tabella attributi di talune method_info strutture (§4.6), vale a dire quelli rappresentano elementi di tipi di annotazione. L'attributo AnnotationDefault registra il valore predefinito per l'elemento rappresentato dalla struttura method_info.

Ogni struttura method_info che rappresenta un elemento di un tipo di annotazione può contenere al massimo un attributo AnnotationDefault. La macchina virtuale Java deve rendere disponibile questo valore predefinito in modo che possa essere applicato dalle API riflettenti appropriate.

Alla fine si invocherà il metodo value() dell'istanza di annotazione (o qualunque altro metodo definito) e restituirà tale valore.

4

Se si cerca il codice byte per l'annotazione , verrà visualizzato il valore predefinito. Utilizzo di javap -c -v e ritaglio degli elementi non pertinenti:

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