5

I am trying to get a Spring Cloud Netflix Feign client to fetch a bit of JSON over HTTP and convert it to an object. I keep getting this error instead:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class io.urig.checkout.Book] and content type [application/json;charset=UTF-8]

Here's the bit of JSON returned from the remote service:

{
    "id": 1,
    "title": "Moby Dick",
    "author": "Herman Melville"
}

Here's the corresponding class I'm trying to deserialize to:

package io.urig.checkout;

public class Book {
    private long id;
    private String title;
    private String author;

    public Book() {}

    public Book(long id, String title, String author) {
        super();
        this.id = id;
        this.title = title;
        this.author = author;
    }

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
}

And here's my Feign client:

package io.urig.checkout;

import java.util.Optional;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import io.urig.checkout.Book;

@FeignClient(name="inventory", url="http://localhost:8080/")
public interface InventoryClient {

    @RequestMapping(method = RequestMethod.GET, value = "books/{bookId}")
    public Optional<Book> getBookById(@PathVariable(value="bookId") Long bookId);

}

What do I need to do to get this to work?

urig
  • 16,016
  • 26
  • 115
  • 184

7 Answers7

4

I don't know Feign, but when I've had "no suitable HttpMessageConverter found..." errors in the past, it's because the content type has not been registered. Perhaps you need to add this to the RequestMapping:

consumes = "application/json"

All I can suggest is to try to confirm if Feign configuration has MappingJackson2HttpMessageConverter registered as a converter for Book. Not sure if this is something that should work out of the box with Feign, or if you have to do it manually. I see an example on Feign's GitHub that has:

GitHub github = Feign.builder()
                 .encoder(new JacksonEncoder())
                 .decoder(new JacksonDecoder())
                 .target(GitHub.class, "https://api.github.com");

Have you created configuration using Feign.builder() or some equivalent configuration files?

RBH
  • 261
  • 1
  • 10
  • 1
    Thank you but unfortunately this did not work. Yields the exact same error message. – urig Mar 09 '18 at 15:00
3

You will need to ensure that you have at least one JSON library on your classpath. Feign supports both GSON and Jackson and Spring Cloud OpenFeign will autoconfigure the SpringEncoder and SpringDecoder instances with the appropriate MessageConverter if they are found on your classpath. Ensure that you have at least one of the following in your pom.xml or build.gradle

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.4</version>
</dependency>

or

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.2</version>
</dependency>

Once they are found, Spring will register the appropriate MessageConverter

Kevin Davis
  • 1,193
  • 8
  • 14
  • 2
    Thanks. I don't know which impl is running underneath. I went fairly basic based on this example: https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html . Also, changing from `Optional` to `Book` still gives the error. – urig Mar 09 '18 at 19:06
  • I have reworded my post to provide an attempt at an answer. – Kevin Davis Mar 09 '18 at 22:24
  • Hi Kevin. Thanks for your help! Sorry for the somewhat critical responses you sometimes get when starting here at SO. Turns out my issue was a defective Maven dependency and deleting it in the .m2 folder cleared things up. There was no need to add explicit dependencies on JSON libraries in pom.xml. At least one of these comes in with Feign itself, I believe it's GSON. – urig Mar 10 '18 at 08:31
1

I think your problem is the response type. Try converting it to Book from Optional. If you want to return an Optional than you should provide your custom converter.

FDirlikli
  • 185
  • 1
  • 4
1

Sorry, for too late answer.

Had the same problem.

Just add two parameters to your @RequestMapping -

consumes = "application/json", produces = "application/json"

In your code this will look like this -

package io.urig.checkout;

import java.util.Optional;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import io.urig.checkout.Book;

@FeignClient(name="inventory", url="http://localhost:8080/")
public interface InventoryClient {

@RequestMapping(method = RequestMethod.GET, value = "books/{bookId}", consumes = "application/json", produces = "application/json")
public Optional<Book> getBookById(@PathVariable(value="bookId") Long bookId);

}
Konstantin
  • 63
  • 8
0

Thanks to all who tried to help!

As it turned out my issue was a defective Maven dependency, probably corrupted during download or installation. Having entirely deleted the .m2/repository folder on my machine and then updating Maven dependencies for the project the issue is now gone.

urig
  • 16,016
  • 26
  • 115
  • 184
0

I am late here but I would like to add one more point. In my case I observed Spring Feign client returns this exception when you specified the return type as a specific model/entity class and that entity is not found.

You should check the response for the another service which you are calling and see what response it returns in case the entity is not found, or in case an exception is thrown.

So in case an entity is not found or any exception is thrown and that response does not match to what you have specified in return type then this exception is thrown in the client service.

GenZ Dev
  • 210
  • 4
  • 16
0

I got the same sort of error from a @PostMapping in my FeignClient, as a side-effect from an error in the PostMapping Annotation's path param. It related to my FeignClient referring to a properties file, for its reference there of the value for the path param:

@PostMapping(path = "{my.property-name-from-properties-file}")

The property reference for path wasn't resolving correctly, and once I solved that, it solved the feign.codec.DecodeException in Question here. (and was troubleshooted first, by giving the path value a hard-coded String, instead of the property value reference).

In my case, I had forgotten the $ char needed to be prepended:

@PostMapping(path = "${my.property-name-from-properties-file}")
cellepo
  • 4,001
  • 2
  • 38
  • 57