Community
Participate
Working Groups
Let's assume I want to intercept method calls whenever a method parameter type contains a field with a certain annotation: package de.scrum_master.app; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(RUNTIME) @Target(FIELD) public @interface MyAnnotation {} ------------------------------------------------------------ package de.scrum_master.app; public class MyClass { private int id; @MyAnnotation private String name; public MyClass(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "MyClass [id=" + id + ", name=" + name + "]"; } } ------------------------------------------------------------ package de.scrum_master.app; public class Application { public void doSomething() {} public void doSomethingElse(int i, String string) {} public void doSomethingSpecial(int i, MyClass myClass) {} public int doSomethingVerySpecial(MyClass myClass) { return 0; } public static void main(String[] args) { Application application = new Application(); application.doSomething(); application.doSomethingElse(7, "foo"); application.doSomethingSpecial(3, new MyClass(11, "John Doe")); application.doSomethingVerySpecial(new MyClass(22, "Jane Doe")); } } Now in native syntax we could just make each target class implement a marker interface and then intercept method calls with parameters of that interface type: package de.scrum_master.app; public interface HasMyAnnotationField {} ------------------------------------------------------------ package de.scrum_master.aspect; import de.scrum_master.app.HasMyAnnotationField; import de.scrum_master.app.MyAnnotation; public aspect MyNativeSyntaxAspect { declare parents : hasfield(@MyAnnotation * *) implements HasMyAnnotationField; before() : execution(* *(.., HasMyAnnotationField+, ..)) { System.out.println(thisJoinPoint); } } When compiled with -XhasMember, this would print: execution(void de.scrum_master.app.Application.doSomethingSpecial(int, MyClass)) execution(int de.scrum_master.app.Application.doSomethingVerySpecial(MyClass)) Now if I am trying to to the same with @AspectJ syntax: package de.scrum_master.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.DeclareParents; import de.scrum_master.app.HasMyAnnotationField; @Aspect public class MyAnnotationSyntaxAspect { @DeclareParents("hasfield(@de.scrum_master.app.MyAnnotation * *)") private HasMyAnnotationField hasMyAnnotationField; @Before("execution(* *(.., de.scrum_master.app.HasMyAnnotationField+, ..))") public void myAdvice(JoinPoint thisJoinPoint) { System.out.println(thisJoinPoint); } } It compiled nicely but @DeclareParents has no effect according to 'javap -p'. It gets even weirder when I change the aspect like this: @DeclareParents("de.scrum_master.app.MyClass") private HasMyAnnotationField hasMyAnnotationField; Now 'javap -p' does show that MyClass implements the interface, but still the advice does not get triggered. I also tried to add a default implementation to the interface, no dice. I even tried the alternative approach with @DeclareMixin, which I am not very familiar with, again without any effect. But maybe I made a mistake there. I am not an Ajc expert and know there are limitations concerning what can be expressed in @AspectJ style. But actually I see no obvious reason why this should not work.
BTW, this is where my question initially came from: https://stackoverflow.com/a/56788724/1082681