user3723501
user3723501

Reputation: 51

AspectJ - Multiple @annotation Pointcut

I can't make a pointcut with "||" operator and multiple annotations. I'm trying to create a Pointcut for some JBehave annotations (@Given, @Then, @When).

This works fine:

    @Pointcut("@annotation(given)")
    public void jBehaveGivenPointcut(Given given) { }

and if I create and advice arount it, it also works.

What would be the syntax for making the Pointcut for the three annotations? Since I had used the logical OR operator in other pointcuts I would assume it is something like:

    @Pointcut("@annotation(given) || @annotation(then) || @annotation(when) ")
    public void jBehaveGivenPointcut(Given given, Then then, When when) { }

but it doesn't work, I get an inconsist binding exception. I tried other combinations but couldn't find the one that does the trick.

Upvotes: 4

Views: 6927

Answers (2)

kriegaex
kriegaex

Reputation: 67297

What you want cannot be done this way because, as the error message says, the annotation binding is inconsistent: You cannot bind all three annotations at the same time because they are in (possibly mutually exclusive) OR parts of the pointcut, i.e. usually only of of them can be bound (unless you assign multiple annotations to the same method). Your expectation might be that AspectJ can deal with this inconsistency by just assigning null to the other two if one is bound, but this is not how the compiler works right now.

I can offer a workaround which involves reflection instead of using the @annotation() binding.

Driver application:

package de.scrum_master.app;

import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;

public class Application {
    public static void main(String[] args) {
        doGiven("foo");
        doSomething("bar");
        doWhen(11);
        doSomethingElse(22);
        doThen();
    }

    @Given("an input value") public static void doGiven(String string) {}
    @When("I do something") public static void doWhen(int i) {}
    @Then("I should obtain a result") public static boolean doThen() { return true; }
    public static void doSomething(String string) {}
    public static void doSomethingElse(int i) {}
}

Aspect:

package de.scrum_master.aspect;

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

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
public class JBehaveInterceptor {
    @Pointcut("execution(@org.jbehave.core.annotations.* * *(..))")
    public void jBehavePointcut() {}

    @Before("jBehavePointcut()")
    public void jBehaveAdvice(JoinPoint.StaticPart thisJoinPointStaticPart) {
        Method method = ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod();
        for (Annotation jBehaveAnnotation : method.getAnnotations()) {
            if (jBehaveAnnotation.annotationType().getPackage().getName().equals("org.jbehave.core.annotations"))
                System.out.println(thisJoinPointStaticPart + " -> " + jBehaveAnnotation);
        }
    }
}

As you can see, the pointcut only intercepts methods annotated by org.jbehave.core.annotations.* which narrows down pointcut matching considerably - to more than just @Given, @When, @Then, but maybe that is even what you want because JBehave offers more annotations than just those.

In the advice we loop over all method annotations because there might be more than just the JBehave ones. If any annotation package name matches the corresponding JBehave package, we do something (in this case print the annotation to standard output).

I cannot extend the AspectJ language for you, this is the best I can think of. Anyway, this yields the following output:

execution(void de.scrum_master.app.Application.doGiven(String)) -> @org.jbehave.core.annotations.Given(priority=0, value=an input value)
execution(void de.scrum_master.app.Application.doWhen(int)) -> @org.jbehave.core.annotations.When(priority=0, value=I do something)
execution(boolean de.scrum_master.app.Application.doThen()) -> @org.jbehave.core.annotations.Then(priority=0, value=I should obtain a result)

Upvotes: 5

codependent
codependent

Reputation: 24442

This works:

@Component
@Aspect
@RequiredArgsConstructor
public class PermissionAspect {

    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void getMapping(){}

    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void postMapping(){}

    @Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping)")
    public void putMapping(){}

    @Pointcut("@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    public void deleteMapping(){}

    @Around("(execution(* xx.*.controller.*.*(..))) && (getMapping() || postMapping() || putMapping() || deleteMapping())")
    Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

Upvotes: 4

Related Questions