You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
When trying out the new polymorphic deserialization feature that is new in JSON-B 3.0 on the Yasson 3.0.0-RC1 JSON-B provider, I noticed that it worked well in the basic scenario of a type with subtypes, but when more subtypes were added to a subtype, then the first-level subtype itself lost its @type property in the generated JSON, causing it to be unable to deserialize. In the following test output, you can see that the third list element lacks a "@type":"area" in its JSON, and then the error which goes along with that,
Converted list of locations to JSON as:
[{"@type":"area","@area":"city","name":"Some City","population":2000,"state":"Some State"},
{"@type":"area","@area":"state","name":"Some State","population":1000000,"capital":"Some Capital City"},
{"name":"North America","population":600000000}]
Apr 06, 2022 11:19:54 AM org.eclipse.yasson.internal.DeserializationContextImpl deserializeItem
SEVERE: Cannot infer a type for unmarshalling into: TestPolymorphism$Location
Exception in thread "main" jakarta.json.bind.JsonbException: Cannot infer a type for unmarshalling into: TestPolymorphism$Location
at org.eclipse.yasson.internal.deserializer.DefaultObjectInstanceCreator.<init>(DefaultObjectInstanceCreator.java:41)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createObjectDeserializer(DeserializationModelCreator.java:251)
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:487)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.typeProcessor(DeserializationModelCreator.java:476)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.typeProcessor(DeserializationModelCreator.java:429)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.createArrayDeserializer(DeserializationModelCreator.java:333)
at org.eclipse.yasson.internal.deserializer.DeserializationModelCreator.deserializerChainInternal(DeserializationModelCreator.java:187)
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:141)
at org.eclipse.yasson.internal.DeserializationContextImpl.deserialize(DeserializationContextImpl.java:131)
at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:55)
at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:62)
at TestPolymorphism.main(TestPolymorphism.java:69)
I found that you can work around this by awkwardly declaring the subtype to be a subtype of itself,
@JsonbTypeInfo(key = "@area", value = {
...
@JsonbSubtype(alias = "general", type = Area.class)
})
public static class Area implements Location {
import jakarta.json.bind.*;
import jakarta.json.bind.annotation.*;
import java.util.*;
public class TestPolymorphism {
@JsonbTypeInfo({
@JsonbSubtype(alias = "point", type = Point.class),
@JsonbSubtype(alias = "area", type = Area.class)
})
public static interface Location {
}
@JsonbTypeInfo(key = "@area", value = {
@JsonbSubtype(alias = "city", type = City.class),
@JsonbSubtype(alias = "state", type = State.class),
// Workaround here - It is awkward that Area must include itself
// as a subtype of itself, but if we don't do this, Yasson also
// omits "@type": "area" from the JSON, making it unable to
// deserialize as a Location.class.
// --- Comment out the following annotation to make it fail ---
//@JsonbSubtype(alias = "general", type = Area.class)
})
public static class Area implements Location {
public String name;
public long population;
}
public static class City extends Area {
public String state;
}
public static class State extends Area {
public String capital;
}
public static class Point implements Location {
public double x;
public double y;
}
public static void main(String[] args) throws Exception {
try (Jsonb jsonb = JsonbBuilder.create()) {
Location[] list = new Location[3];
City city = new City();
city.name = "Some City";
city.population = 2000;
city.state = "Some State";
list[0] = city;
State state = new State();
state.name = "Some State";
state.population = 1000000;
state.capital = "Some Capital City";
list[1] = state;
Area northAmerica = new Area();
northAmerica.name = "North America";
northAmerica.population = 600000000;
list[2] = northAmerica;
String json = jsonb.toJson(list);
System.out.println("Converted list of locations to JSON as:");
System.out.println(json);
Location[] deserialized = jsonb.fromJson(json, Location[].class);
City c = (City) deserialized[0];
assertEquals(city.name, c.name);
assertEquals(city.population, c.population);
assertEquals(city.state, c.state);
State s = (State) deserialized[1];
assertEquals(state.name, s.name);
assertEquals(state.population, s.population);
assertEquals(state.capital, s.capital);
Area a = (Area) deserialized[2];
assertEquals(northAmerica.name, a.name);
assertEquals(northAmerica.population, a.population);
}
}
private static final void assertEquals(Object expected, Object observed) {
if (!Objects.equals(expected, observed))
throw new AssertionError("Expected " + expected + ", but observed " + observed);
}
}
Expected behavior
The third list element of the test output JSON array (without the workaround enabled) should look like this, including @type,
Describe the bug
When trying out the new polymorphic deserialization feature that is new in JSON-B 3.0 on the Yasson 3.0.0-RC1 JSON-B provider, I noticed that it worked well in the basic scenario of a type with subtypes, but when more subtypes were added to a subtype, then the first-level subtype itself lost its
@type
property in the generated JSON, causing it to be unable to deserialize. In the following test output, you can see that the third list element lacks a"@type":"area"
in its JSON, and then the error which goes along with that,I found that you can work around this by awkwardly declaring the subtype to be a subtype of itself,
in which case the
@type
gets added back in,but that should not be necessary.
To Reproduce
Run this test case:
Expected behavior
The third list element of the test output JSON array (without the workaround enabled) should look like this, including
@type
,and then it would deserialize properly because the necessary type information would be found there.
System information:
Additional context
Add any other context about the problem here.
The text was updated successfully, but these errors were encountered: