TheRealJimShady
TheRealJimShady

Reputation: 4303

How do you provide a pointcut bound annotation to an advice method?

So I've defined pointcuts for all methods and all classes of a particular annotation... what I want to do is retrieve the annotation value on every method call. Here is what I have so far

@Aspect
public class MyAspect {

    @Pointcut("execution(* my.stuff..*(..))")
    private void allMethods(){}

    @Pointcut("within(@my.stuff.MyAnnotation*)")
    private void myAnnotations(){}

    @Pointcut("allMethods() && myAnnotations()")
    private void myAnnotatedClassMethods(){}

    @Before("myAnnotatedClassMethods()")
    private void beforeMyAnnotatedClassMethods(){
        System.out.println("my annotated class method detected.");
        // I'd like to be able to access my class level annotation's value here.

    }

}

Upvotes: 1

Views: 224

Answers (1)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279970

Yes, you can have Spring AOP supply the value of the annotation annotating your target object's class.

You'll have to use the binding forms documented in the specification and propagate an argument across your @Pointcut methods.

For example

@Pointcut("execution(* my.stuff..*(..))")
private void allMethods() {
}

@Pointcut("@within(myAnnotation)")
private void myAnnotations(MyAnnotation myAnnotation) {
}

@Pointcut("allMethods() && myAnnotations(myAnnotation)")
private void myAnnotatedClassMethods(MyAnnotation myAnnotation) {
}

@Before("myAnnotatedClassMethods(myAnnotation)")
private void beforeMyAnnotatedClassMethods(MyAnnotation myAnnotation){
    System.out.println("my annotated class method detected: " + myAnnotation);
}

Spring, starting from the myAnnotations pointcut, will match the name given in @within with a method parameter and use that to determine the annotation type. That is then propagated down to the beforeMyAnnotatedClassMethods advice through the myAnnotatedClassMethods pointcut.

The Spring AOP stack will then lookup the annotation value before invoking your @Before method and pass it as an argument.


An alternative, if you don't like the solution above, is to simply provide a JoinPoint parameter in your advice method. You can use it to resolve the target instance with getTarget and use that value to get the class annotation. For example,

@Before("myAnnotatedClassMethods()")
private void beforeMyAnnotatedClassMethods(JoinPoint joinPoint) {
    System.out.println("my annotated class method detected: " + joinPoint.getTarget().getClass().getAnnotation(MyAnnotation.class));
}

I'm unsure how this will behave if the target is further wrapped in other proxies. The annotation might be "hidden" behind proxy classes. Use it carefully.

Upvotes: 1

Related Questions