question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feign + interface inheritance + fallback => Ambiguous mapping

See original GitHub issue

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 :

  • One Api interface in a dedicated gradle module
@RequestMapping("/api/student")
public interface StudentAPI {

    @GetMapping("/options/names")
    List<String> optionNames();
}
  • One Backend module exposing a rest controller in SpringBoot
@RestController
public class StudentApiImpl implements StudentAPI { ...}
  • One edge SpringBoot application consuming Backend using Feign + Fallback

@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

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:14 (6 by maintainers)

github_iconTop GitHub Comments

13reactions
AdamHeidfeldcommented, May 9, 2018

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.

3reactions
Ryan-Miaocommented, Jul 5, 2018

requestmapping

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:

shared api module:

@RequestMapping("/api/v1/users")
public interface UserApi {

    @GetMapping("/")
    List<UserVo> list();

    @GetMapping("/fallback")
    String fallback();
}

provider-demo

@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.");
    }
}

consumer-demo

@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 {
Read more comments on GitHub >

github_iconTop Results From Across the Web

Feign + interface inheritance + fallback => Ambiguous mapping
Feign + interface inheritance + fallback => Ambiguous mapping ... Trying to combine to elements from the documentation : fallback https://cloud.
Read more >
Feign with Hystrix Fallback throwing bean error on startup
@FeignClient(name = "CUSTOMERSERVICE", fallback ... Error seems to be because of the @RequestMapping provided at the class/interface level.
Read more >
Spring Cloud OpenFeign
Feign supports boilerplate apis via single-inheritance interfaces. This allows grouping common operations into convenient base interfaces. UserService.java.
Read more >
Fallbacks with Spring Cloud Feign - Arnold Galovics
One way to implement a fallback for a Spring Cloud Feign client is to create a class that implements the Feign client interface...
Read more >
feign Ambiguous mapping 解决方式_c764193441的博客
Feign Ambiguous mapping 解决方式背景feign在使用过程中,一般先定义接口, ... 如下所示@FeignClient(name = "shore-app")public interface StoreApi ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found