Search code examples
javaspringspring-bootaopaspectj

How does AspectJ match @annotation advice expression with an annotation even when the expression in a different case (small case)?


@Auditable(value=1)
public ResponseEntity upload(@RequestParam file){
    // Code
}

This code is using an @Auditable annotation given below:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
    Integer value() default 0;
}

I have an aspect as follows

@Before("@annotation(auditable)")
public void audit(Integer auditable) {
  AuditCode code = auditable;
  // ...
}

In the above example how is the @Auditable expression being matched to @annotation(auditable) expression even though the A letter in @Auditable is in uppercase whereas in @annotation(auditable) the letter a is in lowercase?

I tried reading the documentation but it just presents the facts without explaining the boundaries of annotation expression matching and in what scenarios it can fail. I was expecting the annotation matching to be case sensitive but I think something deeper is going on like object creation of the @Auditable annotation and then that object is somehow being matched with the Aspect.


Solution

  • Annotations in Spring AOP or AspectJ are matched by their types. The syntax is

    • either @annotation(my.package.MyAnnotation)
    • or @annotation(myAnnotationParameter) in combination with an advice parameter like MyAnnotation myAnnotationParameter, e.g.
    @Before("@annotation(auditable)")
    public void audit(Auditable auditable) {
      System.out.println(auditable.value());
      // ...
    }
    

    or, if you need the joinpoint,

    @Before("@annotation(auditable)")
    public void audit(JoinPoint joinPoint, Auditable auditable) {
      System.out.println(joinPoint + " -> " + auditable.value());
      // ...
    }
    

    If the annotation parameter is bound to an advice parameter like this, its name in the advice method signature and in the pointcut should exactly match, i.e. in a case-sensitive way.

    But your example does not make any sense, and I doubt that you found it in any tutorial like that:

    @Before("@annotation(auditable)")
    public void audit(Integer auditable) { // ⚡
      AuditCode code = auditable;          // ⚡
      // ...
    }
    

    This would not match, because Integer is not an annotation type. It would not even compile, because you cannot assign an Integer to whatever type AuditCode is meant to be - unless AuditCode happens to be an Integer subclass, which is impossible because Integer is a final class.

    Next time, please do not post untested pseudo code that you wrote directly on Stack Overflow, but code you actually compiled and ran on your local machine.