Problem
With the below setup:
public static class PlayResponseValue {
private final String result;
@ConstructorProperties("result")
public PlayResponseValue(String result) {
this.result = result;
}
public String getResult() {
return this.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)
When trying to deserialize the object, but everything works perfectly when using a java application (non native).
Initially discovered when using a feign client, but it is reproducible by just using rest template.
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.
@OlgaMaciaszek was able to reproduce this on this branch. See instructions how to build and how to run
Personally I believe the issue might be with AbstractJackson2HttpMessageConverter
, please have a look.
Workarounds
Everything works in either case:
- if the DTO is re-implemented to be a java
record
. - when
@JsonCreator
is added to the constructor
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.
Environment
- Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.9+11.1 (build 17.0.9+11-LTS-jvmci-23.0-b21, mixed mode, sharing)
- Spring Boot 3.1.6
- OpenFeign 4.0.4
Related Issues
- https://github.com/spring-cloud/spring-cloud-openfeign/issues/966
- https://github.com/spring-projects/spring-boot/issues/39197
Comment From: sdeleuze
This is caused by a missing declared constructors reflection entry for com.fasterxml.jackson.databind.ext.Java7SupportImpl
, see related Java7Support.java source code.
This needs to be handled on https://github.com/oracle/graalvm-reachability-metadata side, I will create related PR.