Problem:
With the below setup:
@FeignClient(name = "play-client", configuration = PlayClientConfiguration.class)
public interface PlayClient {
@GetMapping("/play-value")
PlayResponseValue playValue(@RequestParam String item);
@lombok.Value
class PlayResponseValue {
String result;
}
}
I'm getting the following exception:
Caused by: org.springframework.web.client.RestClientException: Error while extracting response for type [class com.playtika.services.samples.PlayClient$PlayResponseValue] and content type [application/json]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:118)
at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:75)
at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:61)
at feign.optionals.OptionalDecoder.decode(OptionalDecoder.java:36)
at feign.InvocationContext.proceed(InvocationContext.java:36)
... 37 common frames omitted
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.playtika.services.samples.PlayClient$PlayResponseValue` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:406)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:354)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103)
... 41 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.playtika.services.samples.PlayClient$PlayResponseValue` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1739)
But everything works perfectly when using a java application (non native).
Investigation results:
At first I thought this was a hint issue, but I checked and they were indeed automatically generated.
{
"name": "com.playtika.services.samples.PlayClient$PlayResponseValue",
"allDeclaredConstructors": true,
"allDeclaredFields": true,
"methods": [ { "name": "getResult", "parameterTypes": [ ] } ]
}
I tried adding the constructor as a method hint manually, but that didn't help.
I also attempted to solve this by adding:
lombok.anyConstructor.addConstructorProperties=true, which ensured that this was my class file:
public static final class PlayResponseValue {
private final String result;
@ConstructorProperties({"result"})
@Generated
public PlayResponseValue(final String result) {
this.result = result;
}
@Generated
public String getResult() {
return this.result;
}
...
}
but that didn't help.
Workarounds:
Everything works in either case:
* if the DTO is reimplemented to be a java record.
* when @lombok.RequiredArgsConstructor(onConstructor_={@JsonCreator}) is added to the dto
These workarounds are generally acceptable, although would require a lot of effort to implement across multiple services.
Since the constructor is present, the hint for it as well, I believe that native should be able to detect everything just as java would.
Comment From: wilkinsona
I don't think Spring Boot is likely to be the cause here. Please report this to the Spring Cloud OpenFeign project so that they can investigate.
Comment From: dpozinen
reopened in https://github.com/spring-cloud/spring-cloud-openfeign/issues/966