2010-09-18 9 views
15

ho scritto un'annotazione personalizzata contenente i metadati per una proprietà e un AnnotationProcessor:Java 6 - processore di annotazione e il codice Inoltre

@SupportedAnnotationTypes({"<package>.Property"}) 
public class PropertyProcessor extends AbstractProcessor { 

    @Override 
    public boolean process(Set<? extends TypeElement> annotations, 
      RoundEnvironment roundEnv) { 
     // Get messager object 
     Messager messager = processingEnv.getMessager(); 
     // Iterate through the annotations 
     for(TypeElement typeElement : annotations) { 
      // Iterate through the annotated elements 
      for(Element element : roundEnv.getElementsAnnotatedWith(typeElement)) { 
       // Get Property annotation 
       Property property = element.getAnnotation(Property.class); 

      } 
     } 
     return false; 
    } 

} 

Ecco la domanda, ho usato Javassist prima, ma è stato in funzione del caricatore di classe e penso che non sia appropriato per le applicazioni OSGi. Voglio cambiare il bytecode generato quando una classe con annotazione Property è compilata.

+0

una domanda - perché è necessario? Non può essere raggiunto in un altro modo? – Bozho

+0

senza utilizzare APT o questa API, avrò bisogno di annotare entrambi i metodi setter e getter per ogni proprietà, ma se funziona, avrò il controllo completo su come verrà generato il codice. questa non è una pura questione di affari, voglio sapere se questo è possibile o no –

risposta

5

La risposta breve è: non è necessario modificare il codice sorgente durante l'elaborazione delle annotazioni.

Recentemente ho avuto una situazione in cui tale risposta non era soddisfacente (vedere this question). Le mie soluzioni consistevano nell'aggiungere a livello di programmazione il codice che mi serviva usando l'API javac interno. Vedi my answer to my own question per i dettagli.

Mi sono ispirato a questo da Project Lombok, iniziando con il loro codice sorgente e buttando via tutto ciò di cui non avevo bisogno. Non penso che troverai un punto di partenza molto migliore.

BTW, Javassist probabilmente non sarà di aiuto, poiché si tratta di un albero di sorgenti, non di un codice byte. Se si desidera utilizzare una libreria di manipolazione del codice byte, è possibile eseguirla staticamente dopo la compilazione o dinamicamente durante il caricamento delle classi, ma non durante l'elaborazione delle annotazioni, poiché si tratta di una fase di pre-compilazione.

6

Hai provato Google Guice?

Google Guice consente di eseguire un po 'di programmazione orientata agli aspetti intercettando i metodi. Se questo è tutto ciò che devi fare, puoi implementare un MethodInterceptor che ti permetterà di sovrascrivere i metodi in fase di runtime. È davvero utile isolare le preoccupazioni trasversali.

Per esempio, diciamo che si desidera evitare che un certi metodi venga eseguito durante il fine settimana, è possibile annotare come così:

@Property 
public class SomeClass { 
    public Receipt doSometing() { 
     // Do something 
    } 
} 

Definire un MethodInterceptor:

public class PropertyInterceptor implements MethodInterceptor { 
    public Object invoke(MethodInvocation invocation) throws Throwable { 
    // For example prevent the classes annotated with @Property 
    // from being called on weekends 
    Calendar today = new GregorianCalendar(); 
    if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) { 
     throw new IllegalStateException(
      invocation.getMethod().getName() + " not allowed on weekends!"); 
    } 
    return invocation.proceed(); 
    } 
} 

e quindi associare l'intercettore all'annotazione:

public class PropertyModule extends AbstractModule { 
    protected void configure() { 
     PropertyInterceptor propertyInterceptor = new PropertyInterceptor();   
     bindInterceptor(Matchers.annotatedWith(Property.class), 
     Matchers.any(), propertyInterceptor); 
    } 
} 
1

L'elaborazione di annotazione non è destinata a modificare classi esistenti - è solo per generare codice/risorse aggiuntive (su base classe per classe, altrimenti si incontrano problemi quando si ricompilano solo le fonti modificate).

Qualche tempo fa ho provato Spoon per un problema simile: mi piaceva l'idea di un processore di programma molto (e l'integrazione IDE anche di più), ma non è stato davvero stabile al momento ...

A seconda del tuo caso d'uso, uno strumento AOP (ad esempio: AspectJ) potrebbe essere meglio di Spoon e, naturalmente, potresti sempre utilizzare un generatore di codice sorgente o implementare un DSL completo (dai un'occhiata al fantastico Xtext) .

A seconda delle dimensioni, del tasso di turnover e "inerzia intellettuale" dei tuoi compagni di squadra, potresti stare meglio a sopportare i dolori di plain java anziché quelli di introdurre un nuovo strumento/tecnologia, formare collaboratori e integrare il nuovo strumento nel tuo sistema di CI. Pesare attentamente i costi/benefici.