AspectJ: Applying Advice to Methods Based on an Annotation

I am new to AspectJ (not new to AOP though) and have been recently doing some R&D on using AspectJ for intercepting methods annotated with an annotation.

What I Tried …
Use AspectJ to intercept all the public methods (belonging to classes of specified packages) based on an annotation applied.

What I Needed …
Aspect J Development Tool plugin for eclipse. [equipped my eclipse 3.7 with AJDT plugin]
Searched for AspectJ getting started tutorials available on the internet. [Visit this link  for a good AspectJ getting started tutorial]
Searched how to write a pointcut for intercepting a method based on annotation.

This is how I did it …

Created a simple annotation named MyAnnotation.

MyAnnotation.java

package com.technicalmusings.examples.aspectj.annotation;

public @interface MyAnnotation {}


Created three classes Hello1, Hello2 and Hello3 having public and private methods annotated with MyAnnotation. The intent was to apply a before advice to all the public methods (annotated with MyAnnotation) present in the package com.technicalmusings.examples and its sub-packages. Therefore these three classes have been kept in three different packages. Please refer to the class organization in the screenshot below:

AspectJProjectOrganization

Hello1 class has a method without annotation as well to ensure that the pointcuts are doing exactly what they are supposed to.

Hello1.java

package com.technicalmusings.examples.hello1;
import com.technicalmusings.examples.aspectj.annotation.MyAnnotation;

public class Hello1 {

    public static void main(String[] args) {
        methodOfHello1WithoutAnnotation();
        greetPubliclyFromHello1();
    }

    public static void methodOfHello1WithoutAnnotation() {
        System.out.println("Greetings from a method without annotation from Hello1 class!");
    }

    @MyAnnotation
    public static void greetPubliclyFromHello1() {
        System.out.println("Greetings from public method of Hello1 class!");
    }
}


Hello2.java

package com.technicalmusings.examples.aspectj.hello2;
import com.technicalmusings.examples.aspectj.annotation.MyAnnotation;

public class Hello2 {

    public static void main(String[] args) {
        greetPubliclyFromHello2();
        greetPrivatelyFromHello2();
    }

    @MyAnnotation
    public static void greetPubliclyFromHello2() {
        System.out.println("Greetings from public method of Hello2 class!");
    }

    @MyAnnotation
    private static void greetPrivatelyFromHello2() {
        System.out.println("Greetings from private method of Hello2 class!");
    }
}

Hello3.java

package com.technicalmusings.partofexamples;
import com.technicalmusings.examples.aspectj.annotation.MyAnnotation;

public class Hello3 {

    public static void main(String[] args) {
        greetPrivatelyFromHello3();
        greetPubliclyFromHello3();
    }

    @MyAnnotation
    public static void greetPubliclyFromHello3() {
        System.out.println("Greetings from public method of Hello3 class!");
    }

    @MyAnnotation
    private static void greetPrivatelyFromHello3() {
        System.out.println("Greetings from private method of Hello3 class!");
    }
}

Now the important part, the AspectJ stuff…

Created an aspect, HelloAspect, with one after advice and one before advice (just to differentiate between the two scenario)
a) The after advice is applied to all the methods annotated with MyAnnotation (irrespective of package)
b) The before advice is applied to all the mehods anotated with MyAnnotation belonging to classes of specified package or subpackages

HelloAspect.aj

package com.technicalmusings.examples;

public aspect HelloAspect {

    // Pointcut for all public methods
    pointcut publicPointcut(): execution(public * *(..));

    // Pointcut for all the methods with the specified annotation
    pointcut annotationPointcutAll()
        : execution(@com.technicalmusings.examples.aspectj.annotation.MyAnnotation * *(..));

    // Pointcut for all the methods with the specified annotation within specified package
    pointcut annotationPointcutPackage()
        : execution( @com.technicalmusings.examples.aspectj.annotation.MyAnnotation
         * com.technicalmusings.examples..*(..));

    after() : annotationPointcutAll() && publicPointcut() {
        System.out.println("annotationPointcutAll: Intercepted the after call of : " 
        + thisJoinPoint.getSignature());
    }

    before() : annotationPointcutPackage() && publicPointcut() {
        System.out.println("annotationPointcutPackage: Intercepted the before call of : "
        + thisJoinPoint.getSignature());
    }
}

By executing the classes Hello1, Hello2 and Hello3 individually, we can see how the advices are being applied. The after advice which does not have the package filter should include the method of Hello3 class whereas the other should not.

Below snapshot from ‘Cross References’ view of eclipse shows how the HelloAspect is advising the methods.

HelloAdvice

Enjoy Learning,
Kamlesh