RequestMapping inheritence between class level and method level - java

Given the #Controller below, even if i send a Get Request to the webApp, the controller run the homePage method.
#RestController
#RequestMapping(method = RequestMethod.POST)
public class MyController {
#GetMapping("/hello")
public String homePage() {
return "Hello, It is my first application";
}
}
How could that happen? Normally, i restrict that from the class level.

Your method with #GetMapping("/hello") picked up as most specific and enables GET requests with /hello path
This annotation can be used both at the class and at the method level. In most cases, at the method level applications will prefer to use one of the HTTP method specific variants #GetMapping

Related

Is a specific #RequestMapping always called in favour of a variable #RequestMapping in Spring

Let's assume following controller:
#RestController
public class MyController {
#RequestMapping(method = GET, path = "/info")
public InfoModel getInfo(){
...
}
#RequestMapping(method = GET, path = "/{resourceId}")
public ResourceModel getResource(#PathVariable("resourceId") String resourceId){
...
}
}
The question is: Which method will be invoked when curling GET /info.
In all my tests getInfo was called which seems to be clear.
But I'm not 100% sure if this is just a lucky race condition or if it is specified that a static path has a higher precedence than a variable path.
Even after some research I couldn't find the specification for this case, only some pretty old (and probably outdated) blog posts.
I'm using SpringBoot 2.0.2.
It’s not a lucky race condition. The pattern with no path variables will always take precedence.
Please refer to the Spring MVC documentation that explains everything in detail Request Mapping under Pattern Comparison.
If you have the path specified at class level (#RequestMapping("/home") as per below
#RestController
#RequestMapping("/home")
public class MyController {
#RequestMapping(method = GET, path = "/info")
public InfoModel getInfo(){
...
}
}
then you would have to curl GET /home/info. All urls path are defined/decided by you.

How can I specify method with an parameterized annotation and its value with #Pointcut

Background:
I am developing an web application with Spring MVC.
I want to make an aspect that is executed on POST requests and not executed on GET requests, because I want to inject the logic that prevent POST requests which are sent before completion of HTML rendering.
#RequestMapping(value = "/aaa", method = RequestMethod.POST)
public String methodForPost(AnDto dto, Model model) {
// the aspect should be executed on this method
}
#RequestMapping(value = "/bbb", method = RequestMethod.GET)
public String methodForGET(AnDto dto, Model model) {
// the aspect shouldn't be executed on this method
}
Question:
How can I specify method with an parameterized annotation and its value with #Pointcut ?
How can I specify method with an parameterized annotation and its value in <aop:pointcut> in Spring applicationContext.xml?
#Around(value="#annotation(RequestMapping)")
public Object display(ProceedingJoinPoint joinPoint, RequestMapping requestMapping ) throws Throwable {
// You have access to requestMapping. From which you can get whether its get or post and decide to proceed or not.
}
More info http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj-advice-params-passing
You might have to extend this to intercept only for Requestmapping's in your package. Because this intercepts every RequestMappig you might have in your project including one used by the libraries which you might be using, which is a burden.

Difference between the annotations #GetMapping and #RequestMapping(method = RequestMethod.GET)

What's the difference between #GetMapping and #RequestMapping(method = RequestMethod.GET)?
I've seen in some Spring Reactive examples, that
#GetMapping was used instead of #RequestMapping
#GetMapping is a composed annotation that acts as a shortcut for #RequestMapping(method = RequestMethod.GET).
#GetMapping is the newer annotaion.
It supports consumes
Consume options are :
consumes = "text/plain"
consumes = {"text/plain", "application/*"}
For Further details see:
GetMapping Annotation
or read:
request mapping variants
RequestMapping supports consumes as well
GetMapping we can apply only on method level and RequestMapping annotation we can apply on class level and as well as on method level
As you can see here:
Specifically, #GetMapping is a composed annotation that acts as a
shortcut for #RequestMapping(method = RequestMethod.GET).
Difference between #GetMapping & #RequestMapping
#GetMapping supports the consumes attribute like
#RequestMapping.
#RequestMapping is a class level
#GetMapping is a method-level
With sprint Spring 4.3. and up things have changed. Now you can use #GetMapping on the method that will handle the http request. The class-level #RequestMapping specification is refined with the (method-level)#GetMapping annotation
Here is an example:
#Slf4j
#Controller
#RequestMapping("/orders")/* The #Request-Mapping annotation, when applied
at the class level, specifies the kind of requests
that this controller handles*/
public class OrderController {
#GetMapping("/current")/*#GetMapping paired with the classlevel
#RequestMapping, specifies that when an
HTTP GET request is received for /order,
orderForm() will be called to handle the request..*/
public String orderForm(Model model) {
model.addAttribute("order", new Order());
return "orderForm";
}
}
Prior to Spring 4.3, it was #RequestMapping(method=RequestMethod.GET)
Extra reading from a book authored by Craig Walls
Short answer:
There is no difference in semantic.
Specifically, #GetMapping is a composed annotation that acts as a
shortcut for #RequestMapping(method = RequestMethod.GET).
Further reading:
RequestMapping can be used at class level:
This annotation can be used both at the class and at the method level.
In most cases, at the method level applications will prefer to use one
of the HTTP method specific variants #GetMapping, #PostMapping,
#PutMapping, #DeleteMapping, or #PatchMapping.
while GetMapping only applies to method:
Annotation for mapping HTTP GET requests onto specific handler
methods.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/GetMapping.html
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html
`#RequestMapping` since 2.5
=> Can handle all HTTP methods
=> Applicable to class and method
=> Can be used as a substitute of #Controller and #RestController, If we use it
along with #Component.
`#GetMapping` since 4.3
=> Can handle only GET method of HTTP
=> Applicable to method only
#GetMapping is a specific type of #RequestMapping(method = RequestMethod.GET). Both supports consumes
#RequestMapping supports consumes even with method=GET, while #GetMapping doesn't supports consumes.
#RequestMapping is Method & Type level annotation, while #GetMapping is a Method level annotation
Other than that #GetMapping is same as #RequestMapping(method=RequestMethod.GET)
#GetMapping is the shortcut for #RequestMapping(method = RequestMethod.GET)
#RequestMapping is a class level
#GetMapping is a method-level
4)The #RequestMapping annotation is used to map web requests to specific handler classes and functions. This annotations key advantage is that it may be used on both the controller class and methods.
5)It is always advised to be specific while declaring #RequestMapping on the controller methods as in most mapping handler classes, #Getmapping is not used.

#requestmapping precendence order query for Spring

Trying to understand the order in which #RequestMapping in Spring MVC works. I have two different controllers as follows
#Controller
public class TestController {
#RequestMapping(value="/test", method=RequestMethod.GET, produces="application/json")
public #ResponseBody RequestResponse test() {
log.info("test processed");
....
}
}
#Controller
#RequestMapping("/user")
public class UserController {
#RequestMapping(value="/test", method=RequestMethod.GET, produces="application/json")
public #ResponseBody RequestResponse userTest() {
log.info("user test processed");
....
}
}
When I make a request www.test.com/user/test, I was expecting UserController.userTest() method to be called, but what I see is that TestController.test() method is being called.
Here's the logging turned on for Spring
DEBUG; tid:http-bio-8080-exec-8; DispatcherServlet; DispatcherServlet with name 'dispatcher' processing GET request for [/test-web/user/test]
DEBUG; tid:http-bio-8080-exec-8; AbstractHandlerMethodMapping; Looking up handler method for path /test
DEBUG; tid:http-bio-8080-exec-8; AbstractHandlerMethodMapping; Returning handler method [public com.test.dto.RequestResponse com.test.controller.TestController.test()]
DEBUG; tid:http-bio-8080-exec-8; AbstractBeanFactory; Returning cached instance of singleton bean 'testController'
Can someone clarify on the order of Type and Method level #RequestMapping order or any documentation about this?
Debugged some more and based on the debugging I can deduce that the way it seems to be working (and this is by no means an answer to my question) is that AbstractHandlerMethodMapping in Spring evaluates the requests from right to left.
For an incoming request /user/test, AbstractHandlerMethodMapping would first lookup any handler method for /test, if found (which in my case it does) it would pass the request to that method - TestController.test(), in this case. If it doesn't find any mapped handler methods then it would look for any handler method for /user/test.
I find that a bit bizzare, but this is what I have observed in the logs. Can anyone substantiate this with some official documentation?
First class-level RequestMapping is checked and then the method-level one. So the behavior you're telling is not possible afaik.

Spring 3.1.0 mvc binding modelattribute along with requestbody

I am new to Spring 3.1.0, and am trying to create an application, which can be exposed as a web application as well as web services.
For a POST where i am submitting a form object using the #ModelAttribute. I also want to expose this method which can consume the same object as XML, through any poster.
Shall i use both #ModelAttribute & #RequestBody together. I have already added the consumes property in the #RequestMapping annotation.
When you submit form, data comes in form-encoded manner, and when you use XML/JSON it comes as a string in body. You'd better place all your common logic to intermediate service layer and call it in your controllers. As a result it allows you to simply build REST services on top of existing HTML pages with forms:
public class Service {
public void registerUser(User user){
}
}
#RequestMapping("users")
public class FormController{
#Autowired private Service service;
#RequestMapping("register")
public ModelAndView registerUser(#ModelAttribute User user){
service.registerUser(user);
}
}
#RequestMapping("service/v1")
public class RESTController{
#Autowired private Service service;
#RequestMapping("users/register")
public ModelAndView registerUser(#RequestBody User user){
service.registerUser(user);
}
}
Actually, you can even put this in one controller.

Categories

Resources