If I have Annotation:
@Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Loggable { enum LogLevel { ERROR, WARN, INFO, DEBUG, TRACE; } LogLevel value() default DEBUG; }
and trying to use it as target marker of Spring AOP aspect joinpoint marker, it works well for some aspect, weaved by that composite pointcut:
@Aspect class LoggableAspect { @Pointcut("within(@Loggable *)") void aClass() {} //@Pointcut("@annotation(Loggable)") - in straight-forward case it works too! @Pointcut("execution(@Loggable * *(..))") void method() {} @Around("method() || aClass()") Object aroundAdvice(ProceedingJoinPoint pjp) {...} }
In other words, it works well as “straight-forward” annotation usage, when I write code like this:
@Component public class Abc { @Loggable public String method(int x) { return "string: " + x; } }
But in case of META-annotation…:
@Loggable(INFO) @Retention(RUNTIME) public @interface Log { }
…it doesn’t work for example, in that code:
@Component public class Abc { @Log // doesn't work! :( public String method(int x) { return "string: " + x; } }
Certainly, I can write yet another pointcut for that particular case of 2-level deepness:
//... @Pointcut("execution(@(@Loggable *) * *(..))") void metaMethod() {} @Around("method() || metaMethod() || aClass()") Object aroundAdvice(ProceedingJoinPoint pjp) {...}
and it will work, but I want universal solution, working on any level of deepness – 3, 4, 5… Is it possible for that style of AOP?
P.S. That issue:
execution(public * ((@Transactional *)+).*(..))
looks like exactly right solution, but unfortunately, it doesn’t work in my case. I think, it’s possible only as AspectJ solution (in *.aj files) – not for Spring AOP. Am I right?..
Advertisement
Answer
The correct answer to your question, even though you might not like it, is: Neither Spring AOP as a syntactical subset of AspectJ nor native AspectJ provide a dedicated syntax to achieve what you wish to do. The best you can actually do is to use a nested syntax like you suggested yourself and use a reasonable number of nesting levels.
In my answer here you find solutions for both class- and method-level meta annotations.
Update: You misunderstood what
execution(public * ((@Transactional *)+).*(..))
means, even though the answer you linked to explains it:
Matches the execution of any public method in a type with the
Transactional
annotation, or any subtype of a type with theTransactional
annotation.
So this syntax is about class inheritance, not about meta annotation nesting. It means that if you have @Transational class Parent
, it would match class Child extends Parent
and class Grandchild extends Child
etc. The syntax should also work in Spring AOP, but that does not solve your problem.