How do you get RequestMapping request in AOP advice from a Spring controller?

15,386

Solution 1

Found the solution.

import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;

@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controller() {}

// In advice
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature .getMethod();
RequestMethod[] requestMethods = method.getAnnotation(RequestMapping.class).method();

Be careful of which class you import.

Solution 2

@AL13N: Your own answer is correct, but you do not need to use reflection if you just bind the annotation to a parameter. Here is an example in POJO + AspectJ. In Spring AOP it should be the same, though:

Sample controller with main method:

package de.scrum_master.app;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MyController {
    @RequestMapping(value="/some/path", method=RequestMethod.POST)
    public void foo() {
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
    }

    public static void main(String[] args) {
        MyController controller = new MyController();
        controller.foo();
        controller.bar();
    }
}

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.web.bind.annotation.RequestMapping;

public aspect RequestMappingInterceptor {
    @Pointcut(
        "within(@org.springframework.stereotype.Controller *) && " +
        "@annotation(requestMapping) && " +
        "execution(* *(..))"
    )
    public void controller(RequestMapping requestMapping) {}

    @Before("controller(requestMapping)")
    public void advice(JoinPoint thisJoinPoint, RequestMapping requestMapping) {
        System.out.println(thisJoinPoint);
        System.out.println("  " + requestMapping);
        System.out.println("  " + requestMapping.method()[0]);
    }
}

BTW, the && execution(* *(..)) part of the pointcut is probably not necessary in Spring AOP because it just knows execution pointcuts anyway. In AspectJ you need to exclude call() and other types of pointcuts because AspectJ is more powerful. It does not hurt though and is safer and more explicit.

Console output:

execution(void de.scrum_master.app.MyController.foo())
  @org.springframework.web.bind.annotation.RequestMapping(headers=[], name=, value=[/some/path], produces=[], method=[POST], params=[], consumes=[])
  POST
foo
bar

Edit: Swapped parameters so as to make the joinpoint the first advice method parameter, because Spring AOP seems to insist on this order while AspectJ does not.

Share:
15,386
Andy Leung
Author by

Andy Leung

Updated on June 05, 2022

Comments

  • Andy Leung
    Andy Leung almost 2 years

    Given some kind of controller with a request mapping

    @RequestMapping(value="/some/path", method=RequestMethod.POST)
    

    How would you retrieve the method value (RequestMethod.POST) in the aspect class?

    I want to keep track of all the controller methods that perform a POST request.

    Thanks

  • Andy Leung
    Andy Leung over 9 years
    I tried your solution and it doesn't seem to be working. Getting error at ::0 formal unbound in pointcut.
  • kriegaex
    kriegaex over 9 years
    It works for me. Did you make a mistake in your copy & paste action?
  • kriegaex
    kriegaex over 9 years
    Somebody mentioned a while ago that for Spring AOP he had to put the JoinPoint parameter at the beginning of the advice signature instead of at the end. I doubt that this is true, but you can try. I am by no means a Spring expert.
  • kriegaex
    kriegaex over 9 years
    As for the possible copy & paste error: Have you noticed that my pointcut has a parameter in its signature? ;-)
  • kriegaex
    kriegaex almost 9 years
    I still think that this is not the way it should be done. My own answer uses canonical AspectJ and does not require reflection.
  • szxnyc
    szxnyc over 8 years
    I too am getting error at ::0 formal unbound in pointcut with this solution. No copy and paste mistake...
  • kriegaex
    kriegaex over 8 years
    The solution definitely works (the console output proves it), I can say nothing else unless you show me your code and configuration.
  • kriegaex
    kriegaex over 8 years
    Why the downvote? Downvotes are reserved for answers showing a significant lack of research effort or being sloppily written. My code is fully self-consistent, compileable and runs. Just try! I even posted the console log. If it does not run in your environment you must have changed something in an incorrect way.
  • khanou
    khanou over 8 years
    @kriegaex I had the same error than Andy (error at ::0 formal unbound in pointcut) until I set the JointPoint as first param in signature