How can I write an aspectj pointcut that applies to method executions which override an interface method with an annotation? For example:
interface A {
@MyAnnotation void method();
}
class B implements A {
void method();
}
The pointcut execution(@MyAnnotation * *.*(..))
does only match if B.method()
carries the annotation itself. Is there another way to do this?
Pointcut is a set of one or more JoinPoint where an advice should be executed. You can specify Pointcuts using expressions or patterns as we will see in our AOP examples. In Spring, Pointcut helps to use specific JoinPoints to apply the advice.
Pointcut is an expression language of spring AOP which is basically used to match the target methods to apply the advice. It has two parts ,one is the method signature comprising of method name and parameters. Other one is the pointcut expression which determines exactly which method we are applying the advice to.
JoinPoint: Joinpoint are points in your program execution where flow of execution got changed like Exception catching, Calling other method. PointCut: PointCut are basically those Joinpoints where you can put your advice(or call aspect). So basically PointCuts are the subset of JoinPoints.
AspectJ provides primitive pointcuts that capture join points at these times. These pointcuts use the dynamic types of their objects to pick out join points. They may also be used to expose the objects used for discrimination. this(Type or Id) target(Type or Id)
As Nicholas pointed out, this is not possible in AspectJ. Here is more proof of why it is not possible (taken from http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-pointcuts-and-advice.html section Annotation Inheritance and pointcut matching):
According to the Java 5 specification, non-type annotations are not inherited, and annotations on types are only inherited if they have the @Inherited meta-annotation. The call to c2.aMethod (that would be b.method() in your example) is not matched because join point matching for modifiers (the visibility modifiers, annotations, and throws clause) is based on the subject of the join point (the method actually being called).
Having suffered from this same issue, I have written a small method/library that would allow you to write pointcuts for such methods. Here is how it would work for your example:
myAnnotationIsExecuted(): execution(public * *.*(..)) &&
if(implementsAnnotation("@MyAnnotation()", thisJoinPoint));
OR
myAnnotationIsExecuted(): execution(public * A+.*(..)) &&
if(implementsAnnotation("@MyAnnotation()", thisJoinPoint));
The method implementsAnnotation(String,JoinPoint)
is coming from the library; a basic method that checks if the implemented methods contain the specified annotation.
More information about the method/library can be found here.
Update
Since it appears that it cannot be done in Spring (see original answer) I would say that you need to add the annotation to each method on the implementing classes. There is an obvious way to do this, but I suppose if you are looking for a more automatic way you will need to write one yourself.
I can imagine some sort of home-grown post-processor that will look for a specific annotation, lets say @ApplyThisAnnotationToAllWhoInheritMe
. Once it finds this annotation, it would scan sourcecode for inheriting members and add the requested annotation where necessary before compilation happens.
Regardless, if you are using Spring AOP to do this, it appears that it needs to be on the implementers method. If the classes you are hoping this will help are out of your control, you may have to write your own Spring AOP tool.
Original Answer
From the Spring 3.0 Documentation:
AspectJ follows Java's rule that annotations on interfaces are not inherited.
I found this bit in section 7.8.2 Other Spring aspects for AspectJ
, which is a part of 7.8 Using AspectJ with Spring applications
, which makes me think this is a global rule.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With