Search code examples
aopaspectj

@AspectJ: Pointcut for any method of custom annotated class


I'm trying to detect in a pointcut any method of a class annotated with my annotation @NFCDisable.

@NFCDisable
public class MyClass { 
    //methods
}

I have tried this:

@Aspect
public class NFCAspect {

    @Before("method()")
    public void exec() {
        //DO SOMETHING
    }

    @Pointcut("@within(NFCDisable) || @annotation(NFCDisable)")
    public void method() {}
}

But it doesn't work. What am I doing wrong?

Thanks.


Solution

  • It works as long as your aspect and annotation are in the same package. Otherwise the aspect should cause compiler errors such as:

    Type referred to is not an annotation type: @missing@
    

    But even if they are in the same package, the pointcut catches way too many joinpoints such as:

    staticinitialization(de.scrum_master.app.MyClass.<clinit>)
    preinitialization(de.scrum_master.app.MyClass())
    initialization(de.scrum_master.app.MyClass())
    execution(de.scrum_master.app.MyClass())
    execution(void de.scrum_master.app.MyClass.foo())
    execution(int de.scrum_master.app.MyClass.bar(String))
    

    This includes static class initialisation, constructor execution and constructor (pre-)initialisation in addition to the method executions you want to see.

    So what do you need to do?

    • Restrict the pointcut to really only target method executions.
    • Use fully qualified class names in annotation-based AspectJ syntax.
    • Make sure your annotation has runtime retention scope.

    Here is a full example:

    package de.scrum_master.app;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NFCDisable {}
    
    package de.scrum_master.app;
    
    @NFCDisable
    public class MyClass {
        public void foo() {}
        public int bar(String text) { return 11; }
    }
    
    package de.scrum_master.app;
    
    public class Application {
        public static void main(String[] args) {
            MyClass myClass = new MyClass();
            myClass.foo();
            myClass.bar("xxx");
        }
    }
    
    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.Pointcut;
    
    @Aspect
    public class NFCAspect {
        @Pointcut("execution (* *(..)) && @within(de.scrum_master.app.NFCDisable)")
        public void method() {}
    
        @Before("method()")
        public void exec(JoinPoint thisJoinPoint) {
            System.out.println(thisJoinPoint);
        }
    }
    

    Console output:

    execution(void de.scrum_master.app.MyClass.foo())
    execution(int de.scrum_master.app.MyClass.bar(String))
    

    P.S.: The pointcut could also be written like this, which is a bit harder to read IMO:

    @Pointcut("execution (* (@de.scrum_master.app.NFCDisable *).*(..))")