Spring AOP point cut for 'nested' annotation

前端 未结 2 1770
独厮守ぢ
独厮守ぢ 2021-01-14 14:46

I need to define a point cut which triggers the execution on all methods of a spring service annotated with a custom annotation. The annotation I would like to define the po

相关标签:
2条回答
  • 2021-01-14 15:15

    This is not a Spring or AspectJ problem. In Java, annotations on interfaces, other annotations or methods are never inherited by implementing classes, classes using annotated annotations or overriding methods. Annotation inheritance only works from classes onto subclasses, but only if the annotation type used in the superclass bears the meta annotation @Inherited.

    Update: Because I have answered this question several times before, I have just documented the problem and also a workaround in Emulate annotation inheritance for interfaces and methods with AspectJ.

    Here is a little proof that what you want does not work and thus also cannot be utilised by an aspect:

    package de.scrum_master.app;
    
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface OuterAnnotation {}
    
    package de.scrum_master.app;
    
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @OuterAnnotation
    public @interface InnerAnnotation {}
    
    package de.scrum_master.app;
    
    import java.lang.annotation.Annotation;
    
    @InnerAnnotation
    public class Application {
        public static void main(String[] args) {
            for (Annotation annotation : Application.class.getAnnotations())
                System.out.println(annotation);
        }
    }
    

    The console output shows that only the inner annotation is seen by the JVM, not the outer one used on the inner annotation:

    @de.scrum_master.app.InnerAnnotation()
    

    Update: Intrigued by Bradley M Handy's answer, I re-checked if it would also work for the situation described in my code, and indeed it does. Thise type of AspectJ syntax was unknown to me, even though I think I know a lot about AspectJ. So thanks, Bradley. :-) This aspect would work:

    package de.scrum_master.aspect;
    
    import de.scrum_master.app.OuterAnnotation;
    
    public aspect MetaAnnotationAspect {
      after() : within(@(@OuterAnnotation *) *) && execution(* *(..)) {
        System.out.println(thisJoinPoint);
      }
    }
    

    Console log when running the application:

    @de.scrum_master.app.InnerAnnotation()
    execution(void de.scrum_master.app.Application.main(String[]))
    
    0 讨论(0)
  • 2021-01-14 15:18

    I had this exact need in an application. I found this answer, but wasn't satisfied this couldn't be done.

    After a bit more searching, I found this cheat sheet for AspectJ/Spring pointcut expressions. The solution in the cheat sheet didn't work exactly as advertised, but I was able to make it work for what I needed.

    @Pointcut("within(@(@Annotation *) *)")
    public void classAnnotatedWithNestedAnnotationOneLevelDeep() { }
    

    I combined this expression with a @within expression for just the @Annotation to get what I wanted to work.

    For method execution:

    @Pointcut("execution(@(@com.someorg.SomeAnnotation *) * *(..))")
    public void methodAnnotatedWithNestedAnnotationOneLevelDeep() { }
    

    I combined this expression with a @annotation expression for just the @Annotation to get what I wanted to work for methods.

    0 讨论(0)
提交回复
热议问题