Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 895
Andy Leung Avatar asked Nov 14 '14 15:11

Andy Leung


People also ask

Which of the GET requests are mapped to following REST controller?

One of the most important annotations in spring is the @RequestMapping Annotation which is used to map HTTP requests to handler methods of MVC and REST controllers.

Which of the following is the method where RequestMapping is used with fallback method?

@RequestMapping fallback method: We can create a fallback method for the controller class to make sure we are catching all the client requests even though there are no matching handler methods. It is useful in sending custom 404 response pages to users when there are no handler methods for the request.


2 Answers

@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.

like image 151
kriegaex Avatar answered Oct 26 '22 11:10

kriegaex


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.

like image 28
Andy Leung Avatar answered Oct 26 '22 12:10

Andy Leung