When an interface has @PathVariable in it, feign fails to generate a client for it.

@FeignClient("HelloServer")
public interface ITestController {

    @RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
    String hello(@PathVariable String name);

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    String hello();

    @RequestMapping(value = "/randomJob", method = RequestMethod.GET)
    JobDto getRandomJob();
}

Client Code:

@SpringBootApplication
@RestController
@ComponentScan("client")
@EnableFeignClients
@EnableDiscoveryClient
public class ClientApplication {

    @Autowired
    ITestController client;

    @RequestMapping("/hello")
    public String hello() {
        return client.hello();
    }

    @RequestMapping("/hello/{name}")
    public String helloWithName(@PathVariable String name) {
        return client.hello(name);
    }

    @RequestMapping("/job")
    public JobDto randomJob() {
        return client.getRandomJob();
    }

    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
}

Exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientApplication': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: client.ITestController client.ClientApplication.client; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client.ITestController': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: PathVariable annotation was empty on param 0.
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1191) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at client.ClientApplication.main(ClientApplication.java:42) [main/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45]
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) [idea_rt.jar:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: client.ITestController client.ClientApplication.client; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client.ITestController': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: PathVariable annotation was empty on param 0.
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 22 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client.ITestController': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: PathVariable annotation was empty on param 0.
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1590) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:254) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 24 common frames omitted
Caused by: java.lang.IllegalStateException: PathVariable annotation was empty on param 0.
    at feign.Util.checkState(Util.java:108) ~[feign-core-8.1.1.jar:8.1.1]
    at org.springframework.cloud.netflix.feign.annotation.PathVariableParameterProcessor.processArgument(PathVariableParameterProcessor.java:49) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
    at org.springframework.cloud.netflix.feign.support.SpringMvcContract.processAnnotationsOnParameter(SpringMvcContract.java:169) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
    at feign.Contract$BaseContract.parseAndValidatateMetadata(Contract.java:75) ~[feign-core-8.1.1.jar:8.1.1]
    at feign.Contract$BaseContract.parseAndValidatateMetadata(Contract.java:49) ~[feign-core-8.1.1.jar:8.1.1]
    at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:137) ~[feign-core-8.1.1.jar:8.1.1]
    at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:55) ~[feign-core-8.1.1.jar:8.1.1]
    at feign.Feign$Builder.target(Feign.java:166) ~[feign-core-8.1.1.jar:8.1.1]
    at org.springframework.cloud.netflix.feign.FeignClientFactoryBean$DefaultTargeter.target(FeignClientFactoryBean.java:203) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
    at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.loadBalance(FeignClientFactoryBean.java:153) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
    at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:173) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    ... 32 common frames omitted

Comment From: Koizumi85

Hello,

not tested, but i believe you have to supply the path variable's name like this in the annotation:

@RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
String hello(@PathVariable("name") String name);

Comment From: spencergibb

@ezraroi, @Koizumi85's suggestion is a good workaround. See #841 for work being done to fix this.

Comment From: ezraroi

Looks like it is solving the issue.

I also noticed that if I have @RequestMapping annotation on the interface, the generated client is ignoring it.


@FeignClient("HelloServer")
@RequestMapping(value = "/api")
public interface ITestController {

    @RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
    String hello(@PathVariable(value = "name") String name);

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    String hello();

    @RequestMapping(value = "/randomJob", method = RequestMethod.GET)
    JobDto getRandomJob();
}

The generated client will not add \api to the requests it is making

Comment From: spencergibb

Putting @RequestMapping on a controller is not currently supported. It causes spring mvc to try and use the feign client as an actual controller.

Comment From: ezraroi

@spencergibb thanks for the quick response

Comment From: cforce

Is there already a request issue to support it?

Comment From: spencergibb

To support what?

Comment From: cforce

Let Mvc detect that a @RequestMapping on (a extended) interface is intensionally used by a @FeignClientto reuse the api contract and not meant to be as own controller instance. Normally thta shall be the case if there is no implementation available for this interface. Its related with https://jira.spring.io/browse/SPR-11055 and https://github.com/spring-projects/spring-framework/pull/976

Comment From: mbenson

The original issue here seems to be the non-defaulted parameter name. This is addressed by #835 .

Comment From: cforce

To support Putting @RequestMapping on a Controller (or some parent in inheritance hierarchy using Scoped interfaces)

Comment From: spencergibb

@cforce that is not this issue.

Comment From: wispycampaign46

@spencergibb what is the mechanism for feignclient annotation to work

Comment From: vbisht21

// you need to add value in path variable as shown below. @FeignClient("HelloServer") public interface ITestController {

@RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
String hello(@PathVariable(value="name") String name);

@RequestMapping(value = "/hello", method = RequestMethod.GET)
String hello();

@RequestMapping(value = "/randomJob", method = RequestMethod.GET)
JobDto getRandomJob();

Comment From: mychalvlcek

I had similar issue after upgrade to Springboot3.2 + java21 and it was caused by older version of maven-compiler-plugin