The spring boot exception IllegalStateException: Ambiguous mapping. Cannot map method occurs when two methods in the rest controller class are configured with the same request mapping url. Two methods in the rest controller class should not be configured using the same url. The exception will be shown as BeanCreationException: Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource in spring boot application.
The ambiguous mapping is determined on the basis of two factors, the request mapping url and the request mapping method. The same url can be configured with two different request mapping methods, GET and POST.
The rest controller can not configure the same url for two different methods, as it can not distinguish which method should be called when a request is received. The spring boot framework will not be able to create the bean controller if two methods are configured with the same url in the controller class.This will throw “There is already ‘Controller’ bean method Controller#method() mapped.” exception
Exception
The exception stack trace will look like the one below. The exception “Ambiguous mapping. Can not map method” will be shown in the console window when the application starts loading the bean controller.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'testController' method
com.test.TestController#helloworld()
to { /welcome}: There is already 'testController' bean method
com.test.TestController#welcomepage() mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1803) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at com.test.SpringHelloWorldJspApplication.main(SpringHelloWorldJspApplication.java:10) [classes/:na]
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'testController' method
com.test.TestController#helloworld()
to { /welcome}: There is already 'testController' bean method
com.test.TestController#welcomepage() mapped.
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:633) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:600) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:318) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:350) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:67) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$1(AbstractHandlerMethodMapping.java:288) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[na:1.8.0_101]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:286) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(AbstractHandlerMethodMapping.java:258) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:217) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:205) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:171) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1799) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
... 16 common frames omitted
Root Cause
The rest controller uniquely identifies the request on the basis of two factors, the request mapping url and the request mapping method. The rest controller can not configure the same url for two separate methods, as it can not distinguish which method should be used when a request is received.
If two methods are configured with the same url in the controller class, the spring boot framework will not be able to create the bean controller. The spring boot framework will throw “BeanCreationException: Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource” error.
How to reproduce this issue
If you create two methods with the same request mapping url and the same request mapping method in the rest controller class, the spring boot application can not map the url to the methods. The “Ambiguous Mapping. Cannot map the ‘Controller’ method” error will be thrown in the spring boot framework.
package com.yawintutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class TestController {
@RequestMapping("/welcome")
public ModelAndView welcomepage() {
return new ModelAndView("welcome");
}
@RequestMapping("/welcome")
public ModelAndView helloworld() {
return new ModelAndView("welcome");
}
}
Solution 1
If two methods contains the same request mapping url configured in a rest controller class, change one url. This will distinguish the controller methods when the url is requested. The two separate request urls are configured using two controller methods. This will solve the exception.
package com.yawintutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class TestController {
@RequestMapping("/welcome")
public ModelAndView welcomepage() {
return new ModelAndView("welcome");
}
@RequestMapping("/hello")
public ModelAndView helloworld() {
return new ModelAndView("welcome");
}
}
Solution 2
The controller methods can be configured using the same request url using different request mapping methods. If two methods are configured with the same url, one using the GET method and the other using the POST method, the rest controller will distinguish by method.
package com.yawintutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class TestController {
@RequestMapping(value="/welcome", method = RequestMethod.GET)
public ModelAndView welcomepage() {
return new ModelAndView("welcome");
}
@RequestMapping(value="/welcome", method = RequestMethod.POST)
public ModelAndView helloworld() {
return new ModelAndView("welcome");
}
}
Solution 3
If the spring boot application is configured with two or more rest controller classes, there may be possible to create the same url with two different methods in multiple rest controller classes. All the rest controller classes must be checked for the url configured in multiple locations. The exception will be resolved by configuring a unique url across all rest controller classes.
WelcomeController.java
package com.yawintutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class WelcomeController {
@RequestMapping("/welcome")
public ModelAndView welcomepage() {
return new ModelAndView("welcome");
}
}
HelloController.java
package com.yawintutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/welcome")
public ModelAndView helloworld() {
return new ModelAndView("welcome");
}
}
To fix the error in the example above, change the url for any of the rest of the controller methods.