Reputation: 6440
We have a servlet defined in our web.xml
:
<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>foo</servlet-name>
<url-pattern>/foo/*</url-pattern>
</servlet-mapping>
In our controller class, we use both @RequestMapping
and @RestController
.
package com.example.foo;
@RestController("/foo/bar/v1")
public class Baz {
@RequestMapping(value="/bar/v1/abc" /* ... */)
public String doXyz() {
Now, I know the Spring documentation for RequestMapping says
When used at the type level, all method-level mappings inherit this primary mapping, narrowing it for a specific handler method.
In other words, when I define a @RequestMapping("/foo")
on class level, anything I define on the method level would be appended. For the example above, if the path was defined in a @RequestMapping("/foo/bar/v1")
on class level, instead of in the @RestController
, I would thus expect /foo/bar/v1/bar/v1/abc
- or /foo/bar/v1/abc
if the path on the method were relative. Is that understanding of mine correct?
Now, apparently, @RestController("/foo/bar/v1")
has the same effect as @RequestMapping("/foo/bar/v1")
in terms of request path mapping - is that observation correct, too?
If not, why does above code still work? Is the /foo/
part picked up from the web.xml
?
Now, if I leave the code as is, the following test fails:
MvcResult result = mockMvc.perform(
get("/foo/bar/v1")
.accept(MediaType.APPLICATION_JSON_VALUE) //...
My guess is it fails because
/foo
prefix@RequestMapping("bar/v1")
on the method level doesn't actually narrow down the one in @restController("/foo/bar/v1")
after all.The error message I get is
javax.servlet.ServletException: No adapter for handler [com.example.foo.Baz@5b800468]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
This is what the context config looks like that the test loads (besides @WebAppConfiguration
):
<context:annotation-config/>
<mvc:annotation-driven/>
<context:component-scan base-package="com.example.foo" />
How do the annotations and web.xml
really work together, and what do I need to configure to make the test pass?
Upvotes: 4
Views: 1988
Reputation: 22442
In other words, when I define a @RequestMapping("/foo") on class level, anything I define on the method level would be appended. For the example above, if the path was defined in a @RequestMapping("/foo/bar/v1") on class level, instead of in the @RestController, I would thus expect /foo/bar/v1/bar/v1/abc - or /foo/bar/v1/abc if the path on the method were relative. Is that understanding of mine correct?
If you define @RequestMapping(value="/foo/bar/v1")
at class level and @RequestMapping(value="/bar/v1/abc")
at method level , then, your complete url will become as /foo/bar/v1/bar/v1/abc
i.e., both the request mapping strings will be appended simply (i.e., it will not work like /foo/bar/v1/abc
)
@RestController("/foo/bar/v1") has the same effect as @RequestMapping("/foo/bar/v1") in terms of request path mapping - is that observation correct, too?
No, it is not the same effect, because when you add @RestController("/foo/bar/v1")
at the class level, this has nothing to do with the request url mapping, rather here, you are simply naming your controller bean as /foo/bar/v1
, this has no effect on request mapping url.
How do the annotations and web.xml really work together, and what do I need to configure to make the test pass?
servlet-mapping
in web.xml only acts as the global url to the DispatcherServlet
(Front Controller) and then the DispatcherServlet will delegate the request to the respective Controller methods by evaluating the url against the RequestMapping
.
In order to make the test pass with the url /foo/bar/v1
, you can map the controller as below:
@RestController
@RequestMapping(value="/foo/")
public class Baz {
@RequestMapping(value="bar/v1", method=RequestMethod.GET)
public String doXyz() {
}
}
Upvotes: 1