4

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 point cut on will be on an other annotation.

@Y
public @interface X {
}

and then the service would be annotated as following

@X
public Service1 {
} 

I tried with the following point cut definition but it only works when @Y is on the service itself, meaning that it doesn't see that the annotation is on @X

@Around("@within(com.mypackage.Y)")
Domeniquetill
  • 108
  • 1
  • 8

2 Answers2

11

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.

Bradley M Handy
  • 603
  • 6
  • 15
  • Cool, man! You are right and I have just updated my answer according to what you said. While it was correct from me to say that annotations are not inherited, indeed AspectJ can infer them indirectly using the syntax you described here. It is not often that I learn something new about AspectJ anymore, but now I just have. – kriegaex Mar 07 '17 at 12:29
3

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. This 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[]))
kriegaex
  • 63,017
  • 15
  • 111
  • 202