When I use Feign Inheritance, I get the following errors:
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'xxxx.UserClient' method
xxx.UserClient#getUser(Long)
to {GET [/v1/users/{id}]}: There is already 'userResource' bean method
xxx.UserResource#getUser(Long) mapped.
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:662)
Because I added the @RequestMapping annotation on the UserService class, just like that:
@RequestMapping("/v1")
public interface UserService {
@RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
User getUser(@PathVariable("id") long id);
}
So Spring MVC thinks that UserClient is also a handler,This will conflict with the UserResource.
Can I submit a pull request to fix this problem?
Comment From: cbezmen
@terminux
Why don't you use path variable @FeignClient(path = "/v1") instead of @RequestMapping("/v1") ?
Comment From: terminux
Sorry, I closed this issue by accident just now.
Comment From: terminux
@terminux
Why don't you use path variable
@FeignClient(path = "/v1")instead of@RequestMapping("/v1")?
@cbezmen
I used Feign Inheritance to reuse the UserService interface, because the code in UserService and UserClient is the same.
(See the sample code:Feign Inheritance)
I think that's one of the reasons why Feign Inheritance was designed, i don't know if that's right?
However, UserService belongs to Web MVC, so you can't avoid using @RequestMapping("/v1")
Comment From: cbezmen
Yes I understand your case and your solution, It seems good.
However, (I am not here to judge you or I am not owner of the project) This may cause some understanding problem. For example: Users can add @RequestMapping annotation next to FeignClient and without using path variable in FeignClient annotation.
In the example below, new url will be /v3/v1/user/1. FeignClient annotation path will be added to path and RequestMapping path will be ignored. I don't know I can explain the confusion in this example.
You should update documentation and test case for your PR.
@FeignClient(name = "userClient", path = "/v3") // This will be added to url
@RequestMapping(value = "/v2") // This will be ignored
public interface UserClient extends UserService {}
@RequestMapping("/v1")
public interface UserService {
@RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
User getUser(@PathVariable("id") long id);
}
Comment From: terminux
@cbezmen
Thanks for your reply,our understanding should be a little different.My English is not very good, but I try to describe as clearly as possible.
The problem I have is not that the path property in @FeignClient conflicts with the value property in @RequestMapping, because @FeignClient is in UserClient and @RequestMapping is in UserService.For example:
@RequestMapping(value = "/v1")
public interface UserService {
@RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
User getUser(@PathVariable("id") long id);
}
@FeignClient(name = "userClient")
public interface UserClient extends UserService {
}
The @RequestMapping(value = "/v1") will be inherited by the UserClient, so there is no need to specify the path attribute of @FeignClient.When the @RequestMapping annotation exists on the class, Spring MVC will think it is a Handler, so it's going to conflict with the UserResource.For example:
@RestController
public class UserResource implements UserService {
}
This is because there will be two identical handlers in the Spring container,so you should filter out the FeignClient from the Spring MVC,the sample code is as follows:
//If the interface has the @FeignClient annotation, there is no need to register it as Handler
@Bean
public WebMvcRegistrations feignClientFilterWebMvcRegistrations() {
return new WebMvcRegistrations() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
@Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) && !AnnotatedElementUtils.hasAnnotation(beanType, FeignClient.class);
}
};
}
};
}
This is the core code of PR,you can review it #565
Comment From: OlgaMaciaszek
@terminux @cbezmen We do not assume that the class that the FeignClient extends. should be a resource/ controller. As you see in the example from the doc, the UserResource is a separate bean that only implements the UserService. Is this scenario not working? I am not really convinced that making the client extend a controller/ resource is a good practice.
Comment From: cbezmen
Hi @OlgaMaciaszek,
I also a bit confused why he wants to use that like that; he will explain it.
Anyway, @RequestMapping is more useful instead of using @FeignClient(path=""). Maybe we @Deprecated path variable and use @RequestMapping in future releases? What you think?
Comment From: terminux
@OlgaMaciaszek Thanks for your reply.
I use @RequestMapping for the following reasons:
-
Use Feign Inheritance to reuse
UserServiceinterface, because the code inUserServiceandUserClientis the same,so@RequestMappingwill be integrated byUserClient -
As @cbezmen said:
@RequestMapping is more useful instead of using @FeignClient(path="")
because Contract of Spring Cloud OpenFeign uses SpringMvcContract by default (1.2. Overriding Feign Defaults) ,@RequestMapping can be applied to methods but not to classes, which is a bit strange.
Comment From: OlgaMaciaszek
Anyway, @RequestMapping is more useful instead of using @FeignClient(path=""). Maybe we @Deprecated path variable and use @RequestMapping in future releases? What you think?
Not necessarily - it is the way of passing configuration around for any client in Spring Cloud, for example also @LoadBalancerClient, @RibbonClient. Also, a feign client is not a resource, so though it allows easy mapping of methods via @RequestMapping, the interface as a whole generates client, hence configured with client-specific annotations rather than resource/controller-specific annotations.
Comment From: spring-cloud-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-cloud-issues
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.