I need to deserialize JSON looks like the following:
{
"data": [{
"id": "id1",
"type": "type1"
"name": "John",
...
},
{
"id": "id2",
"type": "type2",
"name": "Rebecca",
...
},
{
"id": "id3",
"type": "unknown",
"name": "Peter",
...
}]
}
For deserializing JSON which I have written above I have created a couple of classes:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type",
defaultImpl = DefaultData.class
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Type1Data.class, name = "type1"),
@JsonSubTypes.Type(value = Type2Data.class, name = "type2")
})
public class AbstractData {
public final String id;
public final String type;
public final String name;
public AbstractData(String id, String type, String name) {
this.id = id;
this.type = type;
this.name = name;
}
}
public class Type1Data extends AbstractData {
@JsonCreator
public Type1Data(@JsonProperty("id") String id,
@JsonProperty("name") String name
) {
super(id, "type1", name);
}
}
public class DefaultData extends AbstractData {
@JsonCreator
public DefaultData(@JsonProperty("id") String id,
@JsonProperty("type") String type,
@JsonProperty("name") String name
) {
super(id, type, name);
}
}
public class Main {
public static void main(String... args) {
ObjectMapper mapper = new ObjectMapper();
AbstractData data = mapper.readValue(json, AbstractData.class);
}
}
I get an exception if I use default implementation:
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'unknown' as a type
The class DefaultData
I need to avoid a deserialization exception if I will get the unknown type.
How can I fix this issue?
Right now it is not clear what is the exact root cause of the problem, because your example works for me with several corrections.
Still, please, consider the corrections as a draft.
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
import java.util.StringJoiner;
public class RootData {
public final AbstractData[] data;
@JsonCreator
public RootData(@JsonProperty("data") final AbstractData[] data) {
this.data = data;
}
@Override
public String toString() {
return new StringJoiner(", ", RootData.class.getSimpleName() + "[", "]")
.add("data=" + Arrays.toString(data))
.toString();
}
}
AbstractData
data class: Updated to deserialize type
propertyPlease, see the Javadoc:
Note on visibility of type identifier: by default, deserialization (use during reading of JSON) of type identifier is completely handled by Jackson, and is not passed to deserializers. However, if so desired, it is possible to define property
visible = true
in which case property will be passed as-is to deserializers (and set via setter or field) on deserialization.
Updated annotation by adding visible = true
:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type",
visible = true,
defaultImpl = DefaultData.class
)
Additionally, please, see the related question: java - Jackson - @JsonTypeInfo property is being mapped as null?.
toString()
method(Omitted.)
Please, note that I have corrected the JSON document: added the missing comma after "type": "type1"
.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String... args) throws JsonProcessingException {
final String jsonDocumentString =
"""
{
"data": [{
"id": "id1",
"type": "type1",
"name": "John"
},
{
"id": "id2",
"type": "type2",
"name": "Rebecca"
},
{
"id": "id3",
"type": "unknown",
"name": "Peter"
}]
}
""";
final ObjectMapper mapper = new ObjectMapper();
final RootData rootData = mapper.readValue(jsonDocumentString, RootData.class);
System.out.println(rootData);
}
}
The program completes successfully, i.e. without an exception being thrown.
The program outputs:
RootData[data=[Type1Data[id='id1', type='type1', name='John'], Type2Data[id='id2', type='type2', name='Rebecca'], AbstractData[id='id3', type='unknown', name='Peter']]]
The actual result (output) is the same as the expected result.