25

I have a working Feign interface defined as:

@FeignClient("content-link-service")
public interface ContentLinkServiceClient {

    @RequestMapping(method = RequestMethod.GET, value = "/{trackid}/links")
    List<Link> getLinksForTrack(@PathVariable("trackid") Long trackId);

}

If I change this to use @RequestLine

@FeignClient("content-link-service")
public interface ContentLinkServiceClient {

    @RequestLine("GET /{trackid}/links")
    List<Link> getLinksForTrack(@Param("trackid") Long trackId);

}

I get the exception

Caused by: java.lang.IllegalStateException: Method getLinksForTrack not annotated with HTTP method type (ex. GET, POST)

Any ideas why?

4 Answers 4

32

I wouldn't expect this to work.

@RequestLine is a core Feign annotation, but you are using the Spring Cloud @FeignClient which uses Spring MVC annotations.

24

Spring has created their own Feign Contract to allow you to use Spring's @RequestMapping annotations instead of Feigns. You can disable this behavior by including a bean of type feign.Contract.Default in your application context.

If you're using spring-boot (or anything using Java config), including this in an @Configuration class should re-enable Feign's annotations:

@Bean
public Contract useFeignAnnotations() {
    return new Contract.Default();
}
3
  • 2
    And where exactly in the code we should call useFeignAnnotations(). Or is there an internal bean that will read useFeignAnnotations()? I have this problem and added the bean in my config, but as expected it does nothing
    – Alex
    Commented Dec 3, 2020 at 17:00
  • I'm also curious about this^
    – frlzjosh
    Commented Jul 19, 2021 at 18:22
  • @Alex it is basic spring bean postprocessing. just place it on \@Configuration annotated class and make sure its package is included in componet scanning. Commented Apr 2 at 10:32
3

The reason I got this error is that I used both @FeignClient and @RequestLine annotations in my FooClient interface.

Before a fix.

import org.springframework.cloud.openfeign.FeignClient; // @FeignClient
import feign.RequestLine; //  @RequestLine
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("foo")
public interface FooClient {

    @RequestLine("GET /api/v1/foos/{fooId}")
    @Headers("Content-Type: application/json")
    ResponseEntity getFooById(@PathVariable("fooId") Long fooId); // I mistakenly used @PathVariable annotation here, but this should be @Param
}

Then, I got this error.

Caused by: java.lang.IllegalStateException: Method FooClient#getFooById(Long) not annotated with HTTP method type (ex. GET, POST)

After a fix

// removed @FeignClient
// removed @PathVariable
import feign.Param; // Added
import feign.RequestLine; //  @RequestLine

// removed @FeignClient("foo")
public interface FooClient {

    @RequestLine("GET /api/v1/foos/{fooId}")
    @Headers("Content-Type: application/json")
    Foo getFooById(@Param("fooId") Long fooId); // used @Param
}

If you are interested in the configuration classes.

  • Please note that I tried to create Feign Clients Manually.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScans(value = {
        @ComponentScan(basePackages = {
                "com.example.app.service.web.client",
        })
})
public class FeignConfig {
    @Value(value = "${app.foo.service.client.url}")
    protected String url; // http://localhost:8081/app

    @Bean
    public FooClient fooClient() {
        FooClient fooClient = Feign.builder()
//                .client(RibbonClient.create())
                .client(new OkHttpClient())
                .encoder(new GsonEncoder())
                .decoder(new GsonDecoder())
                .logger(new Slf4jLogger(FooClient.class))
                .logLevel(Logger.Level.FULL)
                .target(FooClient.class, url);
        return fooClient;
    }
}

References

  1. https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html
  2. https://www.baeldung.com/intro-to-feign
  3. https://www.baeldung.com/feign-requestline
  4. https://stackoverflow.com/a/32488372/12898581
-1

Your @RequestMapping value looks ok, but you're likely should consider slightly rewriting it:

 @GetMapping(value = "/{trackid}/links")
 List<Link> getLinksForTrack(@PathVariable(name = "trackid") Long trackId);

Btw I did not succeeded with getting @RequestLine to work due to same error as yours.

Also for @ReactiveFeignClients Contract.Default() yields to following errors:

java.lang.IllegalStateException: Method MyClient#doStuff(String,String) not annotated with HTTP method type (ex. GET, POST)
Warnings:
- Class MyClient has annotations [Component, ReactiveFeignClient, Metadata] that are not used by contract Default
- Method doStuff has an annotation GetMapping that is not used by contract Default

and should be fixed like:

var MyClient = WebReactiveFeign.builder()
        .contract(new ReactiveContract(new SpringMvcContract()))
        .target(MyClient, "http://example.com")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.