1

Trying to created a point cut which take parameter from annotation and then can use it further.So far I have reached:

pointcut callDemoAspectPointCut():
      call(Papa+.new()) && @within(MyAnnotation); //With param here

   after() returning(Object r) :callDemoAspectPointCut(){//use param here
      sysout("executed");
}

Please advice ..

xyz
  • 2,160
  • 3
  • 20
  • 31

1 Answers1

1

There are several kinds of annotations you can capture:

  • class annotations
  • method annotations
  • member annotations
  • method parameter annotations

Here is an example for each:

Marker annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int id();
    String name();
}

Driver application using annotations in different places:

package de.scrum_master.app;

@MyAnnotation(id = 1, name = "class")
public class Application {
    @MyAnnotation(id = 2, name = "member")
    private String member = "foo";

    @MyAnnotation(id = 3, name = "method")
    public static void main(String[] args) {
        new Application().doSomething("blah", Math.PI);
    }

    private String doSomething(String text, @MyAnnotation(id = 4, name = "parameter") double number) {
        String returnValue = member + " " + number;
        member = text;
        return returnValue;
    }
}

Aspect capturing annotations:

Most of the pointcut/advice pairs are quite elegant. But unfortunately you need some rather ugly reflection to get hold of parameter annotations.

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.SoftException;
import org.aspectj.lang.reflect.MethodSignature;

import de.scrum_master.app.MyAnnotation;

public aspect AnnotationParameterAspect {
    pointcut methodExecutionInAnnotatedClass(MyAnnotation myAnnotation) :
        @within(myAnnotation) && execution(* *(..));

    pointcut annotatedMemberReadAccess(MyAnnotation myAnnotation) :
        @annotation(myAnnotation) && get(* *);

    pointcut annotatedMemberWriteAccess(MyAnnotation myAnnotation) :
        @annotation(myAnnotation) && set(* *);

    pointcut annotatedMethodExecution(MyAnnotation myAnnotation) :
        @annotation(myAnnotation) && execution(* *(..));

    pointcut annotatedMethodParameter() :
        execution(* *(.., @MyAnnotation (*), ..));

    after(MyAnnotation myAnnotation) returning(Object returnValue) :
        methodExecutionInAnnotatedClass(myAnnotation)
    {
        System.out.println(thisJoinPoint + " -> " + returnValue);
        printAnnotation(myAnnotation);
    }

    after(MyAnnotation myAnnotation) returning(Object returnValue) :
        annotatedMemberReadAccess(myAnnotation)
    {
        System.out.println(thisJoinPoint + " -> " + returnValue);
        printAnnotation(myAnnotation);
    }

    after(MyAnnotation myAnnotation, Object newValue) :
        annotatedMemberWriteAccess(myAnnotation) && args(newValue)
    {
        System.out.println(thisJoinPoint + " -> " + newValue);
        printAnnotation(myAnnotation);
    }

    after(MyAnnotation myAnnotation) returning(Object returnValue) :
        annotatedMethodExecution(myAnnotation)
    {
        System.out.println(thisJoinPoint + " -> " + returnValue);
        printAnnotation(myAnnotation);
    }

    after() : annotatedMethodParameter() {
        System.out.println(thisJoinPoint);
        MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
        Class<?> clazz = methodSignature.getDeclaringType();
        try {
            Method method = clazz.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            for (Annotation[] parameterAnnotations : method.getParameterAnnotations()) {
                for (Annotation annotation : parameterAnnotations) {
                    if (annotation instanceof MyAnnotation)
                        printAnnotation((MyAnnotation) annotation);
                }
            }
        }
        catch (NoSuchMethodException nsme) {
            throw new SoftException(nsme);
        }
    }

    private static void printAnnotation(MyAnnotation myAnnotation) {
        System.out.println("  " + myAnnotation);
        System.out.println("    id   = " + myAnnotation.id());
        System.out.println("    name = " + myAnnotation.name() + "\n");
    }
}

Console log:

Please note how annotations in different places are logged along with their parameter values:

set(String de.scrum_master.app.Application.member) -> foo
  @de.scrum_master.app.MyAnnotation(id=2, name=member)
    id   = 2
    name = member

get(String de.scrum_master.app.Application.member) -> foo
  @de.scrum_master.app.MyAnnotation(id=2, name=member)
    id   = 2
    name = member

set(String de.scrum_master.app.Application.member) -> blah
  @de.scrum_master.app.MyAnnotation(id=2, name=member)
    id   = 2
    name = member

execution(String de.scrum_master.app.Application.doSomething(String, double)) -> foo 3.141592653589793
  @de.scrum_master.app.MyAnnotation(id=1, name=class)
    id   = 1
    name = class

execution(String de.scrum_master.app.Application.doSomething(String, double))
  @de.scrum_master.app.MyAnnotation(id=4, name=parameter)
    id   = 4
    name = parameter

execution(void de.scrum_master.app.Application.main(String[])) -> null
  @de.scrum_master.app.MyAnnotation(id=1, name=class)
    id   = 1
    name = class

execution(void de.scrum_master.app.Application.main(String[])) -> null
  @de.scrum_master.app.MyAnnotation(id=3, name=method)
    id   = 3
    name = method
kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • 1 more ques : pointcut applyAspect(MyAnnotation myAnnotation) : @within(myAnnotation) && execution(*.new(..)); will this be for annotation over class and execution of ant constructor in the class – xyz Aug 10 '16 at 12:32
  • 1
    Sorry, I was busy. Yes, your assumption is correct. In this case you can get the newly created object via `target()` if you want to log it or do something else with it. BTW, instead of `*.new(..)` you could also just write `new(..)`. – kriegaex Aug 13 '16 at 07:35