Trying to combine to elements from the documentation :
I'm facing IllegalStateException: Ambiguous mapping. Cannot map at springBoot start
According to my understanding it is both good pratices
Build on gradle with
SpringBoot version : 1.5.9.RELEASE
SpringCloud version : Edgware.SR1
Case :
@RequestMapping("/api/student")
public interface StudentAPI {
@GetMapping("/options/names")
List<String> optionNames();
}
@RestController
public class StudentApiImpl implements StudentAPI { ...}
@Controller
@RequestMapping("/web/student")
public class StudentController {
private static final Logger LOG = LoggerFactory.getLogger(StudentController.class);
@Autowired
private StudentApiClient apiClient;
@GetMapping(path = "/notes/{option}")
public String displayStudentNotesForOption(@PathVariable String option, Model model) {
}
@FeignClient(name = "jacademie-student-server", fallback = StudentApiClientFallback.class)
public interface StudentApiClient extends StudentAPI { }
@Component
public class StudentApiClientFallback implements StudentApiClient {
...
}
feign.hystrix.enabled: true
Error is :
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'fr.tse.jacademie.springBoot.student.client.StudentApiClient' method
public abstract java.util.List<java.lang.String> fr.tse.jacademie.springBoot.student.StudentAPI.optionNames()
to {[/api//student/options/names],methods=[GET]}: There is already 'studentApiClientFallback' bean method
public java.util.List<java.lang.String> fr.tse.jacademie.springBoot.student.client.StudentApiClientFallback.optionNames() mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at fr.tse.jacademie.springBoot.student.client.StudentClientApplication.main(StudentClientApplication.java:17) [main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.5.9.RELEASE.jar:1.5.9.RELEASE]
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'fr.tse.jacademie.springBoot.student.client.StudentApiClient' method
public abstract java.util.List<java.lang.String> fr.tse.jacademie.springBoot.student.StudentAPI.optionNames()
to {[/api//student/options/names],methods=[GET]}: There is already 'studentApiClientFallback' bean method
public java.util.List<java.lang.String> fr.tse.jacademie.springBoot.student.client.StudentApiClientFallback.optionNames() mapped.
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.assertUniqueMethodMapping(AbstractHandlerMethodMapping.java:576) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:540) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:264) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:250) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:214) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:184) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:127) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 21 common frames omitted
Can't find any documentation pointing me the missing pieces ... or what I'm doing wrong.
So I think it is a bug
Would it be possible to provide a complete project that reproduces the problem?
ASAP I'll copy paste those sample code into a code archive with build config
@smougenot Hi, maybe you can use @FeignClient(fallback = XxxxFactory.class) instead.
here is my code for example. Sorry, it's scala code, but I am sure it's easy to you.
import com.github.yingzhuo.service.api.{EchoClient => ApiEchoClient}
import org.springframework.cloud.netflix.feign.FeignClient
@FeignClient(name = "node-service-provider", fallbackFactory = classOf[EchoClientFallbackFactory])
trait EchoClient extends ApiEchoClient
import feign.hystrix.FallbackFactory
import org.springframework.stereotype.Component
@Component
class EchoClientFallbackFactory extends FallbackFactory[EchoClient] {
override def create(cause: Throwable): EchoClient = _ => "<fallback>"
}
It worked for me.
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
I met the same problem today. But my feign client declaration code is like this:
@FeignClient(value = "aaa", fallback = ClientFallBack.class)
//@RequestMapping("/aaa/bbb") // <-- THE EVIL CODE
public interface Client {
@RequestMapping(value = "/ccc", method = RequestMethod.GET)
@ResponseBody
public Response function(@RequestParam("ddd") int a);
}
@Component
class ClientFallBack implements Client {
@Override
public Response function(int a) {
return null;
}
}
the "EVIL CODE" line is the key. If we have that line uncommented, the described exception is thrown. If it's not, everything is OK.
Not sure it's the same thing @smougenot is facing. But it's worth mentioning.
Can you provide the complete project that reproduces the problem?
The issue occurs when doing additional request mappings on class/interface level.
I quickly created a minimal working demonstration of this issue.
See: https://github.com/MoritzKrischke/hystrixmappingproblem
I inserted a todo comment on ApiClient where the error occurs.
@MoritzKrischke I cant try to reproduce this because i dont have the "cardealer" service. However I have never seen anyone add a @RequestMapping annotation to a feign client. If you separate the two, I assume you dont see the error right?
Hi @ryanjbaxter, you won´t need the service since the bean wiring fails during startup.
If we remove @RequestMapping on class/interface level the error is gone. As current solution we just merged the @RequestMapping from class/interface level into the declarations made on method level.

The reason why we want add a @RequestMapping is that we make the provider API as a module. So, for the provider, SampleControler implements SampleAPI;
For the consumer, just create an interface SampleClient extend SampleAPI, add an a @FeignClient on it. The consumer do not need write a FeignClient again, just share the same definition from the provider.
For why this error produced, The FeingClient has a @RequestMapping and the fallback has the same @RequestMapping because of the inherent. The key is RequestMappingHandlerMapping bean initialize error.
see
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) {
HandlerMethod handlerMethod = this.mappingLookup.get(mapping);
if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException(
"Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" +
newHandlerMethod + "\nto " + mapping + ": There is already '" +
handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
}
}
I think RequestMappingHandlerMapping scan our FeignClient as an Endpoint.
There is a complete sample:
@RequestMapping("/api/v1/users")
public interface UserApi {
@GetMapping("/")
List<UserVo> list();
@GetMapping("/fallback")
String fallback();
}
@RestController
public class UserController implements UserApi {
private List<User> users = Lists.newArrayList(
new User(1, "谭浩强", 100, LocalDate.now()),
new User(2, "严蔚敏", 120, LocalDate.now()),
new User(3, "谭浩强", 100, LocalDate.now()),
new User(4, "James Gosling", 150, LocalDate.now()),
new User(6, "Doug Lea", 150, LocalDate.now())
);
@Override
public List<UserVo> list() {
return users.stream()
.map(u -> new UserVo(u.getId(), u.getName(), u.getAge(), u.getBirth()))
.collect(Collectors.toList());
}
@Override
public String fallback() {
Random random = new Random();
boolean b = random.nextBoolean();
if (b){
return "success.";
}
throw new RuntimeException("test fallback.");
}
}
@FeignClient( value = "PROVIDER-DEMO", fallback = UserClientFallback.class)
public interface UserClient extends UserApi {
}
@Component
public class UserClientFallback implements UserClient {
@Override
public List<UserVo> list() {
UserVo userVo = new UserVo();
userVo.setAge(1);
userVo.setBirth(LocalDate.now());
userVo.setId(1);
userVo.setName("fallback");
return Lists.newArrayList(userVo);
}
@Override
public String fallback() {
return "this is fallback.";
}
}
So we can just add a different @RequestMapping on the Fallback-Class
@RequestMapping("/will-never-access-this-endpoint")
public class UserClientFallback implements UserClient {
It is a well known issue that feign clients can not have request mappings on the interface.
I have the same problem.
@cjbi
It is a well known issue that feign clients can not have request mappings on the interface.
I had the same issue and i solved it enabling the Hystrix support in Feign, just adding this property to 'application.properties':
feign.hystrix.enabled = true
(I'm using a FallbackFactory)
I thought with Hystrix on the classpath, this would be automatically enabled, but I was wrong :P
I hope this can help.
Most helpful comment
I met the same problem today. But my feign client declaration code is like this:
the "EVIL CODE" line is the key. If we have that line uncommented, the described exception is thrown. If it's not, everything is OK.
Not sure it's the same thing @smougenot is facing. But it's worth mentioning.