We have two classes annotated with @RestController and with the same name in different packages. Since by default the bean name is the class name this generates an issue when booting the application. For this reason, we give a custom name to each class via @RestController
's value
field. However, it appears that when the bean name starts with a /
Spring tries to exposes that name as a servlet path.
Here's an example (I've also attached a .zip with the entire code):
package com.example.demo.namespace1;
@RestController("/potato")
@RequestMapping("/namespace1/demo")
public class DemoController {
@GetMapping
public String handler() {
return "/namespace1/demo";
}
}
package com.example.demo.namespace2;
@RestController("/tomato")
@RequestMapping("/namespace2/demo")
public class DemoController {
@GetMapping
public String handler() {
return "/namespace2/demo";
}
}
The following requests result in:
GET http://localhost:8080/namespace1/demo
-> 200GET http://localhost:8080/namespace2/stuff
-> 404GET http://localhost:8080/potato
-> 500 Stack trace:
2021-10-07 09:41:20.541 ERROR 2749 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [No adapter for handler [com.example.demo.namespace1.DemoController@7e2e9e87]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler] with root cause
javax.servlet.ServletException: No adapter for handler [com.example.demo.namespace1.DemoController@7e2e9e87]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1302) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1050) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.10.jar:5.3.10]
It appears that when the bean name starts with a /
that name tries to be exposed as a servlet path but since there's no handler for that path the request results in an error. This looks suspicious as the behaviour of the application is different depending on the names of the beans.
I was trying to understand if this behaviour is expected but haven't found any mention to this in the documentation so far.
(This might be a Spring issue and not Spring Boot so apologies if opening in the wrong tracker.)
Comment From: sbrannen
I was trying to understand if this behaviour is expected but haven't found any mention to this in the documentation so far.
This is the expected behavior.
Whenever you use @EnableWebMvc
, that automatically imports DelegatingWebMvcConfiguration
which extends WebMvcConfigurationSupport
, and WebMvcConfigurationSupport
automatically registers a BeanNameUrlHandlerMapping
.
The BeanNameUrlHandlerMapping
is what is mapping http://localhost:8080/potato
to your @RestController("/potato")
annotated controller.
In light of that, I am closing this issue.
Comment From: joca-bt
Is there a quick way of disabling BeanNameUrlHandlerMapping
?
Comment From: sbrannen
You should be able to override org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.beanNameHandlerMapping(FormattingConversionService, ResourceUrlProvider)
so that it simply returns null
.
Give that a try and let us know if it works for you.