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
_______________________________________________
aspectj-users mailing list
[email protected]
To change your delivery options, retrieve your password, or unsubscribe from 
this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users

Reply via email to