Issue with @JsonbCreator constructor with Generic Type in Yasson 3.0.0 and higher
There seems to be a bug in Yasson version 3.0.0 and higher that affects the @JsonbCreator constructor when it has a Generic Type parameter. This issue is not present in Yasson version 2.0.4.
Stack trace from the reproducer (version 3.0.0 and higher):
Exception in thread "main" jakarta.json.bind.JsonbException: Error resolving runtime type for type: T
at org.eclipse.yasson.internal.ReflectionUtils.lambda$getRawType$0(ReflectionUtils.java:92)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at org.eclipse.yasson.internal.ReflectionUtils.getRawType(ReflectionUtils.java:92)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createObjectDeserializer(DeserializationModelCreator.java:236)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChainInternal(DeserializationModelCreator.java:193)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChain(DeserializationModelCreator.java:135)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createNewChain(DeserializationModelCreator.java:488)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.typeProcessor(DeserializationModelCreator.java:477)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.typeProcessor(DeserializationModelCreator.java:430)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createCollectionDeserializer(DeserializationModelCreator.java:273)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChainInternal(DeserializationModelCreator.java:183)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChain(DeserializationModelCreator.java:135)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createNewChain(DeserializationModelCreator.java:488)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.typeProcessor(DeserializationModelCreator.java:477)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.typeProcessor(DeserializationModelCreator.java:430)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createObjectDeserializer(DeserializationModelCreator.java:227)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChainInternal(DeserializationModelCreator.java:193)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChain(DeserializationModelCreator.java:135)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChain(DeserializationModelCreator.java:123)
at org.eclipse.yasson.internal.DeserializationContextImpl.deserializeItem(DeserializationContextImpl.java:137)
at org.eclipse.yasson.internal.DeserializationContextImpl.deserialize(DeserializationContextImpl.java:127)
at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:55)
at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:62)
at Reproducer.main(Reproducer.java:27)
Reproducer using JBang:
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.eclipse:yasson:3.0.3
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbConfig;
import jakarta.json.bind.JsonbBuilder;
import jakarta.json.bind.annotation.JsonbCreator;
import java.util.List;
public class Reproducer {
public static void main(String... args) {
Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
.withFormatting(true)
.withNullValues(true));
String jsonString = "{\n" +
" \"id\": 0,\n" +
" \"multiLangRecords\": [{\n" +
" \"lang\": \"\",\n" +
" \"record\": {\n" +
" \"description\": \"\"\n" +
" }\n" +
" }] \n" +
" }";
System.out.println(jsonb.fromJson(jsonString, InsertTechnicalLocationInputJ.class));
// EXPECTED: InsertTechnicalLocationInputJ[id=0, multiLangRecords=[InsertLangEntryGQLJ[lang=, record=InsertTechnicalLocationRecordGQLJ[description=]]]]
}
public record InsertTechnicalLocationInputJ(String id,
List<InsertLangEntryGQLJ<InsertTechnicalLocationRecordGQLJ>> multiLangRecords) {
@JsonbCreator
public InsertTechnicalLocationInputJ {
}
}
public record InsertTechnicalLocationRecordGQLJ(String description) {
@JsonbCreator
public InsertTechnicalLocationRecordGQLJ {
}
}
public record InsertLangEntryGQLJ<T>(String lang, T record) {
@JsonbCreator
public InsertLangEntryGQLJ {
}
}
}
Switching yasson's version (line starting //DEPS) from 3.0.3 to 2.0.4 resolves the issue.
JBang documentation and how to download it: https://www.jbang.dev/
The first commit where this error gets thrown is b74033d Not sure what caused this because the diff is huge
It seems we are facing the same issue using Yasson 3.0.2 (which ships with WildFly 30):
jakarta.ws.rs.ProcessingException: RESTEASY008200: JSON Binding deserialization error: jakarta.json.bind.JsonbException: Error resolving runtime type for type: T
at [email protected]//org.jboss.resteasy.plugins.providers.jsonb.JsonBindingProvider.readFrom(JsonBindingProvider.java:78
[..]
Caused by: jakarta.json.bind.JsonbException: Error resolving runtime type for type: T
at org.eclipse.yasson//org.eclipse.yasson.internal.ReflectionUtils.lambda$getRawType$0(ReflectionUtils.java:92)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at org.eclipse.yasson//org.eclipse.yasson.internal.ReflectionUtils.getRawType(ReflectionUtils.java:92)
at org.eclipse.yasson//org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createObjectDeserializer(DeserializationModelCreator.java:236)
at org.eclipse.yasson//org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChainInternal(DeserializationModelCreator.java:193)
at org.eclipse.yasson//org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChain(DeserializationModelCreator.java:135)
at org.eclipse.yasson//org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChain(DeserializationModelCreator.java:123)
at org.eclipse.yasson//org.eclipse.yasson.internal.DeserializationContextImpl.deserializeItem(DeserializationContextImpl.java:137)
at org.eclipse.yasson//org.eclipse.yasson.internal.DeserializationContextImpl.deserialize(DeserializationContextImpl.java:127)
at org.eclipse.yasson//org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:55)
at org.eclipse.yasson//org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:95)
at [email protected]//org.jboss.resteasy.plugins.providers.jsonb.ManagedJsonb.fromJson(ManagedJsonb.java:73)
at [email protected]//org.jboss.resteasy.plugins.providers.jsonb.JsonBindingProvider.readFrom(JsonBindingProvider.java:71)
```
In our case the Java data class in question which Yasson is trying to deserialize is:
public class RuleResponse<T> {
private final T result;
@JsonbCreator
public RuleResponse(@JsonbProperty("result") final T result) {
this.result = result;
}
public T getResult() {
return result;
}
}
Is there a workaround for this issue? We cannot just downgrade Yasson because Yasson 3 is used internally by WildFly a lot as well it seems.
@edgarvonk Possible workaround was brought up here: https://github.com/smallrye/smallrye-graphql/issues/1819#issuecomment-1549588537
Thanks @mskacelik ! It seems to do the trick indeed. A rather cumbersome workaround for us however since our code base is large with quite a huge number of Java value classes that do not implement an interface nor extend from an abstract class which are used as generic types in JSON deserialisation..
This likely came in on #537. ~~I've locally got a fix for it, but I'm working to see if I can write a test for it.~~ The fix I've got locally fixes a slightly different issue I'm seeing which I'll file an issue and a fix for.