Emulate annotation inheritance for interfaces and methods using AspectJ

Often people ask AspectJ questions like this, so I want to answer it in a place that I can easily contact later.

I have an annotation for this marker:

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 Marker {} 

Now I annotate an interface and / or methods like this:

 package de.scrum_master.app; @Marker public interface MyInterface { void one(); @Marker void two(); } 

Here is a small driver application that also implements the interface:

 package de.scrum_master.app; public class Application implements MyInterface { @Override public void one() {} @Override public void two() {} public static void main(String[] args) { Application application = new Application(); application.one(); application.two(); } } 

Now that I am defining this aspect, I expect it to be launched

  • for each execution of the constructor of the annotated class and
  • for each execution of the annotated method.
 package de.scrum_master.aspect; import de.scrum_master.app.Marker; public aspect MarkerAnnotationInterceptor { after() : execution((@Marker *).new(..)) && !within(MarkerAnnotationInterceptor) { System.out.println(thisJoinPoint); } after() : execution(@Marker * *(..)) && !within(MarkerAnnotationInterceptor) { System.out.println(thisJoinPoint); } } 

Unfortunately, this aspect does not print anything, as if the Application class and the two() method did not contain @Marker annotations. Why doesn't AspectJ intercept them?

+6
source share
1 answer

The problem here is not AspectJ, but the JVM. In Java annotations on

  • interfaces
  • methods or
  • other annotations

never inherited

  • implementing classes
  • overriding methods or
  • classes using annotated annotations.

Inheritance of annotations only works from classes to subclasses, but only if the type of annotation used in the superclass carries the @Inherited @Inherited , see the JavaDoc JDK .

AspectJ is a JVM language and therefore works within the limits of the JVM. There is no general solution to this problem, but for specific interfaces or methods for which you want to emulate annotation inheritance, you can use a workaround similar to the following:

 package de.scrum_master.aspect; import de.scrum_master.app.Marker; import de.scrum_master.app.MyInterface; /** * It is a known JVM limitation that annotations are never inherited from interface * to implementing class or from method to overriding method, see explanation in * <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html">JDK API</a>. * <p> * Here is a little AspectJ trick which does it manually. * */ public aspect MarkerAnnotationInheritor { // Implementing classes should inherit marker annotation declare @type: MyInterface+ : @Marker; // Overriding methods 'two' should inherit marker annotation declare @method : void MyInterface+.two() : @Marker; } 

Note: With this aspect, you can remove (literal) annotations from the interface and from the annotated method, because the AspectJ ITD mechanics (defining between types) add them back to the interface plus to all the implementation / redefinition of classes / methods.

Now, the console log when starting Application says:

 execution(de.scrum_master.app.Application()) execution(void de.scrum_master.app.Application.two()) 

By the way, you can also embed an aspect directly into the interface so that everything is in one place. Just be careful, rename MyInterface.java to MyInterface.aj to help the AspectJ compiler recognize that it needs to do some work here.

 package de.scrum_master.app; public interface MyInterface { void one(); void two(); public static aspect MarkerAnnotationInheritor { // Implementing classes should inherit marker annotation declare @type: MyInterface+ : @Marker; // Overriding methods 'two' should inherit marker annotation declare @method : void MyInterface+.two() : @Marker; } } 
+7
source

Source: https://habr.com/ru/post/976434/


All Articles