Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] How to get inner annotation instance from '@(@Foo *)' expression

This question might be a little esoteric, but still I am wondering how to solve the following problem without using reflection:

Lately I discovered that I can express "classes annotated by some annotation which in turn is annotated by another annotation Y" like this:

    within(@(@Y *) *)

Here is a little example:

-------------------------------------------------

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
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);
  }
}

-------------------------------------------------

Console log:

@de.scrum_master.app.InnerAnnotation()

-------------------------------------------------

Of course, the annotations on interfaces are never inherited or accumulated in any way by the JVM, so it is no surprise that Application has @InnerAnnotation, but not @OuterAnnotation. So far, so good.

But still I am able to say to AspectJ: Give me classes annotated by some annotation X which itself is annotated by @OuterAnnotation:

-------------------------------------------------

package de.scrum_master.aspect;

import de.scrum_master.app.OuterAnnotation;

public aspect MetaAnnotationAspect {
  after() : within(@(@OuterAnnotation *) *) && execution(* *(..)) {
    System.out.println("@OuterAnnotation -> " + thisJoinPoint);
  }
}

-------------------------------------------------

Console log:

@de.scrum_master.app.InnerAnnotation()
@OuterAnnotation -> execution(void de.scrum_master.app.Application.main(String[]))

Besides, this is not just a theoretical example. In Spring you could e.g. want to capture all methods which are somehow connected with @RequestMapping. But obviously current Spring versions use this annotation indirectly by decorating annotations such as  by @GetMapping, @PostMapping by @RequestMapping. Here the syntax mentioned above comes in handy because now you can have a method like

  @GetMapping public void blah()

and capture it like this: 

  after() : execution(@(@RequestMapping *) * *(..)) {
    System.out.println(thisJoinPoint);
  }

This is really useful and it even works recursively. This gets all methods annotated by an annotation @X annotated by another annotation @Y annotated by @Target:

  after() : within(@(@(@Target *) *) *) && execution(* *(..)) {
    System.out.println(thisJoinPoint);
  }


Now here is the actual question: Is there any way other than by reflection that I can bin the inner(most) annotation or any other annotation in the chain to pointcut arguments via @annotation(), @args() or whatever syntactic means so as to be able to inspect its properties? E.g. I could inspect which target types the @Target annotation in the above example has in its ElementType[]. I tried several syntax variations which might have done what I hoped for, such as trying to use (nested) versions of @within() or within(), but other than syntax errors the closest I could get to solving the problem was producing AspectJ compiler error dumps, giving me a slight hope that it might somehow work and just a compiler bug would be in the way.

So much for my (maybe not so) esoteric problem. I do not need it for production today, it is just a nifty little exercise, but I might use it tomorrow or next year if I know that it actually works.

Regards
-- 
Alexander Kriegisch
https://scrum-master.de


Back to the top