2011-08-24 8 views
12

Come posso scrivere un aspectj pointcut che si applica alle esecuzioni del metodo che sovrascrivono un metodo di interfaccia con un'annotazione? Ad esempio:@AspectJ pointcut per metodi che sovrascrivono un metodo di interfaccia con un'annotazione

interface A { 
    @MyAnnotation void method(); 
} 
class B implements A { 
    void method(); 
} 

Il pointcut execution(@MyAnnotation * *.*(..)) fa corrisponde solo se B.method() porta l'annotazione stessa. c'è un altro modo per fare ciò?

risposta

10

Come ha sottolineato Nicholas, questo non è possibile in AspectJ. Qui è più la prova del motivo per cui non è possibile (tratto da http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-pointcuts-and-advice.html sezione Annotazione di successione e la congruenza pointcut):

In base alle specifiche Java 5, non le annotazioni di tipo non sono ereditate, e le annotazioni sui tipi sono solo ereditato se hanno la meta-annotazione @Inherited. La chiamata a c2.aMethod (che sarebbe b.method() nell'esempio) non viene soddisfatta perché la corrispondenza del punto di join per i modificatori (i modificatori di visibilità, le annotazioni e la clausola di ritorno) si basa sull'oggetto del punto di unione (il metodo effettivamente chiamato).

Avendo sofferto di questo stesso problema, ho scritto un piccolo metodo/libreria che consentiva di scrivere collegamenti per tali metodi.Ecco come funzionerebbe per il tuo esempio:

myAnnotationIsExecuted(): execution(public * *.*(..)) && 
      if(implementsAnnotation("@MyAnnotation()", thisJoinPoint)); 

O

myAnnotationIsExecuted(): execution(public * A+.*(..)) && 
      if(implementsAnnotation("@MyAnnotation()", thisJoinPoint)); 

Il metodo implementsAnnotation(String,JoinPoint) sta venendo dalla biblioteca; un metodo di base che controlla se i metodi implementati contengono l'annotazione specificata.

Maggiori informazioni sul metodo/libreria può essere trovato here.

3

Aggiornamento

Poiché sembra che non possa essere fatto in primavera (vedi risposta originale) direi che è necessario aggiungere l'annotazione a ciascun metodo sulle classi di attuazione. C'è un modo ovvio per farlo, ma suppongo che se stai cercando un modo più automatico, dovrai scriverne uno tu stesso.

Posso immaginare una sorta di post-processor cresciuto in casa che cercherà un'annotazione specifica, diciamo @ApplyThisAnnotationToAllWhoInheritMe. Una volta trovata questa annotazione, esegue la scansione del codice sorgente per i membri ereditari e aggiunge l'annotazione richiesta, laddove necessario, prima che avvenga la compilazione.

Indipendentemente da ciò, se si utilizza Spring AOP per farlo, sembra che sia necessario utilizzare il metodo Implementers. Se le lezioni che speri ti aiuteranno saranno fuori dal tuo controllo, potresti dover scrivere il tuo strumento Spring AOP.

risposta originale

Dal Spring 3.0 Documentation:

AspectJ segue la regola di Java che le annotazioni sulle interfacce non vengono ereditati.

Ho trovato questo bit nella sezione 7.8.2 Other Spring aspects for AspectJ, che è una parte di 7.8 Using AspectJ with Spring applications, che mi fa pensare questa è una regola globale.

+0

Grazie; questo spiega perché il mio collegamento non funziona. Comunque, sto cercando uno che funzioni. :-) –

+0

@hstoerr: Dopo aver modificato la tua domanda, ho modificato la mia risposta. Fammi sapere se è ancora inaccettabile. –

+1

La documentazione di primavera in realtà non dice che è impossibile abbinare su qualcosa di simile a quello che voglio - solo che il semplice approccio che ho provato non funziona. Ci potrebbe essere qualche cosa strana che si possa fare in Aspectj a cui non riesco a pensare. Quindi spero ancora. :-) –

2
//introducing empty marker interface 
declare parents : hasmethod(@MyAnnotation * *(..)) implements TrackedParentMarker; 

public pointcut p1() : execution(* TrackedParentMarker+.*(..)); 

Inoltre si dovrebbe consentire -XhasMember flag di compilazione.

+0

Sfortunatamente non è proprio così. Si applica a tutti i metodi di tutte le classi che implementano un'interfaccia che ha almeno un metodo che trasporta l'annotazione. Ma dovrebbe applicarsi solo all'unico metodo che implementa il metodo di interfaccia con quel marcatore. O almeno a metodi che hanno lo stesso nome con il metodo di interfaccia marcato, se è possibile dire in AspectJ. –