Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AspectJ pointcut expression match parameter annotations at any position

I'm trying to define a pointcut expression to match methods which contain a parameter annotated with a specific annotation, regardless of what position the parameter is in. In my case I'm looking for the @Constraint annotation. For example:

Matching methods:

public void method1(@Constraint Car car)

public void method2(String id, @Constraint Plane plane)

public void method3(Wheel wheel, @Constraint List<Train> trains, @Constraint Plane plane)

public void method4(Motor motor, @Constraint Set<Train> trains, Bicycle bike, Wheel wheel)

public void method5(Wing wing, Motorcycle moto, @Constraint Truck truck, Bicycle bike, Wheel wheel)

So far I've tried the following expressions with no luck:

@Before("execution(public * *.*(..)) and @args(com.example.Constraint)") // there can be only one parameter
@Before("execution(public * *.*(..)) and @args(..,com.example.Constraint)") // parameter must be in last position
@Before("execution(public * *.*(..)) and @args(com.example.Constraint,..)") // parameter must be in first position
@Before("execution(public * *.*(..)) and (@args(com.example.Constraint,..) or @args(..,com.example.Constraint))") // parameter must be in first or last position, nothing in between
@Before("execution(public * *.*(..)) and @args(..,com.example.Constraint,..)") // Invalid

Can someone point me to the right solution? is it even possible?

like image 315
driangle Avatar asked Aug 01 '12 19:08

driangle


People also ask

What is the use of @AspectJ annotation in Java?

@AspectJ is mainly used for declaring aspects as regular Java classes annotated with annotations. Spring AspectJ AOP implementation has many annotations. They are explained below: @Aspect: It declares the class as an aspect. @Pointcut: It declares the pointcut expression.

How to combine Pointcut expressions in AspectJ?

In AspectJ, pointcut expressions can be combined with the operators && (and), || (or), and ! (not). e.g. 4.1. Match all methods with names ending with Manager and DAO

Where can I find the complete AspectJ pointcut language?

For complete AspectJ pointcut language, please refer to the AspectJ programming guide available on AspectJ’s web site. 1. How to match method signature patterns The most typical pointcut expressions are used to match a number of methods by their signatures.

What is @AspectJ in spring AspectJ?

@AspectJ is mainly used for declaring aspects as regular Java classes annotated with annotations. Spring AspectJ AOP implementation has many annotations. They are explained below:


Video Answer


2 Answers

You cannot bind an argument at an arbitrary position via args() in AspectJ because this could lead to ambiguity. Just imagine you have two or more parameters of the same type (or annotated by the same annotation type in this case). Which one of them should be bound to the named args() parameter? So while

execution(public * *(.., @Deprecated (*), ..))

is possible as a stand-alone expression (please note the parentheses around the star), it is not possible in combination with args(). So if you do not just want to intercept the method execution itself, but also find the first or all parameters with the given annotation you need to do just what I showed in the other article. I am kinda repeating myself, but so be it in order for the answer not to be deleted again:

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Constraint {}
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Application {
    public void method1(@Constraint int i) {}
    public void method2(String id, @Constraint float f) {}
    public void method3(int i, @Constraint List<String> strings, @Constraint String s) {}
    public void method4(int i, @Constraint Set<Integer> numbers, float f, boolean b) {}
    public void method5(boolean b, String s, @Constraint String s2, float f, int i) {}
    public void notIntercepted(boolean b, String s, String s2, float f, int i) {}

    public static void main(String[] args) {
        List<String> strings = new ArrayList<String>();
        strings.add("foo");
        strings.add("bar");
        Set<Integer> numbers = new HashSet<Integer>();
        numbers.add(11);
        numbers.add(22);
        numbers.add(33);

        Application app = new Application();
        app.method1(1);
        app.method2("foo", 1f);
        app.method3(1, strings, "foo");
        app.method4(1, numbers, 1f, true);
        app.method5(false, "foo", "bar", 1f, 1);
        app.notIntercepted(false, "foo", "bar", 1f, 1);
    }
}
import java.lang.annotation.Annotation;

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

public aspect ArgCatcherAspect {
    before() : execution(public * *(.., @Constraint (*), ..)) {
        System.out.println(thisJoinPointStaticPart);
        MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
        Annotation[][] annotations;
        try {
            annotations = thisJoinPoint.getTarget().getClass().
                getMethod(methodName, parameterTypes).getParameterAnnotations();
        } catch (Exception e) {
            throw new SoftException(e);
        }
        int i = 0;
        for (Object arg : thisJoinPoint.getArgs()) {
            for (Annotation annotation : annotations[i]) {
                if (annotation.annotationType() == Constraint.class)
                    System.out.println("  " + annotation + " -> " + arg);
            }
            i++;
        }
    }
}

As you can see, it is a bit trickier to get the annotations of a given parameter than just its declared type, but basically it works the same way as in my previous post, i.e. by iterating over the list of arguments.

like image 191
kriegaex Avatar answered Oct 04 '22 15:10

kriegaex


I think you want execution(public * *.*(.., @com.example.Constraint *, ..), modulo some syntax.

like image 36
Judge Mental Avatar answered Oct 04 '22 15:10

Judge Mental