Reputation: 16831
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?
Upvotes: 8
Views: 33973
Reputation: 4479
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}")
Upvotes: 0
Reputation: 250
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.
Upvotes: 0
Reputation: 73
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);
}
Upvotes: 1
Reputation: 16831
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.
Upvotes: 1
Reputation: 1293
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
Upvotes: 3
Reputation: 271
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?
Upvotes: 5
Reputation: 195
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.
Upvotes: 2