How to get inner annotation instance from '@(@Foo *)' expression

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

How to get inner annotation instance from '@(@Foo *)' expression

Alexander Kriegisch-2
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
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to get inner annotation instance from '@(@Foo *)' expression

Andy Clement
There is matching for that (was in the original AspectJ 5: https://eclipse.org/aspectj/doc/next/adk15notebook/annotations-pointcuts-and-advice.html ) but no binding as far as I recall.

The compiler dumps that came out are bugs that need fixing for if you try out strange syntax.

I don’t see why we can’t support this but I think any AJ resource for the next little while is going to be around supporting Java9. And I still have the parameter annotation binding feature half done that would be good to finish. I also saw you raise the issue about switching to a maven build, I’d love to do that, but I’ve loved to do that for many years and it never gets to the top of the list!

cheers,
Andy


On Mar 7, 2017, at 9:41 AM, Alexander Kriegisch <[hidden email]> wrote:

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


_______________________________________________
aspectj-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users
Loading...