<p dir="auto"><strong><a href="https://jira.spring.io/secure/ViewProfile.jspa?name=mschipperheyn" rel="nofollow">marc schipperheyn</a></strong> opened <strong><a href="https://jira.spring.io/browse/SPR-9253?redirect=false" rel="nofollow">SPR-9253</a></strong> and commented</p>
<p dir="auto">This is best explained by an example</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@Controller 
@RequestMapping(&quot;/base&quot;)
public class MyController{

	@RequestMapping(method = RequestMethod.GET, value = &quot;/start.html&quot;)
	public String doSomething(
			ModelMap model,
			NativeWebRequest request) throws Exception {
[...]

	@RequestMapping(method = RequestMethod.POST, value = &quot;/start.html&quot;)
	public String doSomething(
			@ModelAttribute(&quot;vo&quot;) MyVO vo,
			BindingResult result,
			ModelMap model,
			NativeWebRequest request) throws Exception {
[...]
}"><pre class="notranslate"><span class="pl-c1">@</span><span class="pl-c1">Controller</span> 
<span class="pl-c1">@</span><span class="pl-c1">RequestMapping</span>(<span class="pl-s">"/base"</span>)
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">MyController</span>{

	<span class="pl-c1">@</span><span class="pl-c1">RequestMapping</span>(<span class="pl-s1">method</span> = <span class="pl-smi">RequestMethod</span>.<span class="pl-c1">GET</span>, <span class="pl-s1">value</span> = <span class="pl-s">"/start.html"</span>)
	<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">doSomething</span>(
			<span class="pl-smi">ModelMap</span> <span class="pl-s1">model</span>,
			<span class="pl-smi">NativeWebRequest</span> <span class="pl-s1">request</span>) <span class="pl-k">throws</span> <span class="pl-smi">Exception</span> {
[...]

	<span class="pl-c1">@</span><span class="pl-c1">RequestMapping</span>(<span class="pl-s1">method</span> = <span class="pl-smi">RequestMethod</span>.<span class="pl-c1">POST</span>, <span class="pl-s1">value</span> = <span class="pl-s">"/start.html"</span>)
	<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-s1">doSomething</span>(
			<span class="pl-c1">@</span><span class="pl-c1">ModelAttribute</span>(<span class="pl-s">"vo"</span>) <span class="pl-smi">MyVO</span> <span class="pl-s1">vo</span>,
			<span class="pl-smi">BindingResult</span> <span class="pl-s1">result</span>,
			<span class="pl-smi">ModelMap</span> <span class="pl-s1">model</span>,
			<span class="pl-smi">NativeWebRequest</span> <span class="pl-s1">request</span>) <span class="pl-k">throws</span> <span class="pl-s1">Exception</span> {
[...]
}</pre></div>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@Controller 
@RequestMapping(&quot;/base/extend&quot;)
public class MyExtendedController extends MyController{

	@RequestMapping(method = RequestMethod.GET, value = &quot;/start.html&quot;)
	public String doSomething(
			ModelMap model,
			NativeWebRequest request) throws Exception {
[...]

	@RequestMapping(method = RequestMethod.POST, value = &quot;/start.html&quot;)
	public String doSomething(
			@ModelAttribute(&quot;vo&quot;) MyVO vo,
			BindingResult result,
			ModelMap model,
			NativeWebRequest request) throws Exception {
[...]
}"><pre class="notranslate"><span class="pl-c1">@</span><span class="pl-c1">Controller</span> 
<span class="pl-c1">@</span><span class="pl-c1">RequestMapping</span>(<span class="pl-s">"/base/extend"</span>)
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">MyExtendedController</span> <span class="pl-k">extends</span> <span class="pl-smi">MyController</span>{

	<span class="pl-c1">@</span><span class="pl-c1">RequestMapping</span>(<span class="pl-s1">method</span> = <span class="pl-smi">RequestMethod</span>.<span class="pl-c1">GET</span>, <span class="pl-s1">value</span> = <span class="pl-s">"/start.html"</span>)
	<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">doSomething</span>(
			<span class="pl-smi">ModelMap</span> <span class="pl-s1">model</span>,
			<span class="pl-smi">NativeWebRequest</span> <span class="pl-s1">request</span>) <span class="pl-k">throws</span> <span class="pl-smi">Exception</span> {
[...]

	<span class="pl-c1">@</span><span class="pl-c1">RequestMapping</span>(<span class="pl-s1">method</span> = <span class="pl-smi">RequestMethod</span>.<span class="pl-c1">POST</span>, <span class="pl-s1">value</span> = <span class="pl-s">"/start.html"</span>)
	<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-s1">doSomething</span>(
			<span class="pl-c1">@</span><span class="pl-c1">ModelAttribute</span>(<span class="pl-s">"vo"</span>) <span class="pl-smi">MyVO</span> <span class="pl-s1">vo</span>,
			<span class="pl-smi">BindingResult</span> <span class="pl-s1">result</span>,
			<span class="pl-smi">ModelMap</span> <span class="pl-s1">model</span>,
			<span class="pl-smi">NativeWebRequest</span> <span class="pl-s1">request</span>) <span class="pl-k">throws</span> <span class="pl-s1">Exception</span> {
[...]
}</pre></div>
<p dir="auto">This will make Spring think start.html occurs twice in the same controller and throw and IllegalStateException.</p>
<p dir="auto">The reason to want to extend controllers is to be able to use common methods.</p>
<p dir="auto">AFAIK, the only way to extend controllers is to use RequestMapping at the Controller level. It is not possible to just use RequestMappings at the method level in this scenario. I consider it very inelegant, especially in the context of REST, that the urlpath has to be unique at an endpoint level ("/start.html"). It should be unique taken into account the entire requestmapping ("/base/start.html", "/base/extend/start.html".</p>
<hr>
<p dir="auto"><strong>Issue Links:</strong></p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398118881" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/14003" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/14003/hovercard" href="https://github.com/spring-projects/spring-framework/issues/14003">#14003</a> Ambiguous handler mapping exception for unambiguous mappings (<em><strong>"duplicates"</strong></em>)</li>
</ul>
<p dir="auto"><strong><a href="https://jira.spring.io/secure/ViewProfile.jspa?name=mschipperheyn" rel="nofollow">marc schipperheyn</a></strong> opened <strong><a href="https://jira.spring.io/browse/SPR-9366?redirect=false" rel="nofollow">SPR-9366</a></strong> and commented</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="@Controller
@RequestMapping(&quot;/my&quot;)
public class MyController extends ExtendedController

@RequestMapping(method = RequestMethod.POST, value = &quot;/post/&quot;)
	public String post(
		@ModelAttribute(&quot;vo&quot;) MyVO vo,
	        BindingResult result,
	        ModelMap model,
	        NativeWebRequest request) throws Exception{
[...]

@Controller
@RequestMapping(&quot;/my/extend&quot;)
public class MyController extends ExtendedController

@RequestMapping(method = RequestMethod.POST, value = &quot;/post/&quot;)
	public String extendPost(
		@ModelAttribute(&quot;vo&quot;) MyVO vo,
	        BindingResult result,
	        ModelMap model,
	        NativeWebRequest request) throws Exception{
"><pre class="notranslate"><code class="notranslate">@Controller
@RequestMapping("/my")
public class MyController extends ExtendedController

@RequestMapping(method = RequestMethod.POST, value = "/post/")
	public String post(
		@ModelAttribute("vo") MyVO vo,
	        BindingResult result,
	        ModelMap model,
	        NativeWebRequest request) throws Exception{
[...]

@Controller
@RequestMapping("/my/extend")
public class MyController extends ExtendedController

@RequestMapping(method = RequestMethod.POST, value = "/post/")
	public String extendPost(
		@ModelAttribute("vo") MyVO vo,
	        BindingResult result,
	        ModelMap model,
	        NativeWebRequest request) throws Exception{

</code></pre></div>
<p dir="auto">This leads to</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path '/my/extend/post/': {public java.lang.String nlproject.controller.MyExtendController.extendPost(nl.project.VO.MyVO,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap,org.springframework.web.context.request.NativeWebRequest) throws java.lang.Exception, public java.lang.String nl.project.controller.MyController.post(nl.project.VO.MyVO,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap,org.springframework.web.context.request.NativeWebRequest)}. If you intend to handle the same path in multiple methods, then factor them out into a dedicated handler class with that path mapped at the type level!
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodResolver.resolveHandlerMethod(AnnotationMethodHandlerAdapter.java:642)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:431)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)"><pre class="notranslate"><code class="notranslate">java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path '/my/extend/post/': {public java.lang.String nlproject.controller.MyExtendController.extendPost(nl.project.VO.MyVO,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap,org.springframework.web.context.request.NativeWebRequest) throws java.lang.Exception, public java.lang.String nl.project.controller.MyController.post(nl.project.VO.MyVO,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap,org.springframework.web.context.request.NativeWebRequest)}. If you intend to handle the same path in multiple methods, then factor them out into a dedicated handler class with that path mapped at the type level!
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodResolver.resolveHandlerMethod(AnnotationMethodHandlerAdapter.java:642)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:431)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
</code></pre></div>
<p dir="auto">The exception suggests that the paths are identical, which they are not. Apparently, Spring checks for path uniqueness at the method level without taking into account the base mapping at the classlevel.</p>
<hr>
<p dir="auto"><strong>Issue Links:</strong></p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398118182" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/13891" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/13891/hovercard" href="https://github.com/spring-projects/spring-framework/issues/13891">#13891</a> Controller extension doesn't allow extending REST Urls (<em><strong>"is duplicated by"</strong></em>)</li>
</ul>