I have a json file which contains an array of mixed types. Its structure look like this:
{
"operations": [
{
"extension": {
"serviceId": "id",
"serviceType": "type"
},
"name": "name",
"tags": "tags"
},
{
"core": {
"config": {
"a": 90,
"b": 45
},
"displayName": "displayName"
},
"name": "name",
"tags": "tags"
},
{
"extension": {
"serviceId": "abc",
"serviceType": "xyz"
},
"name": "name",
"tags": "tags"
}
]
}
Follow this topic Stackoverflow I create my model for json mapping of mixed types.
My java model:
@Data
public class Payload {
private List<OperationElement> operations;
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({ @JsonSubTypes.Type(value = Extension.class, name = "extension"),
@JsonSubTypes.Type(value = Core.class, name = "core") })
public static abstract class OperationElement {
private String name;
private String tags;
}
@Data
@JsonRootName("extension")
public static class Extension extends OperationElement {
private String serviceType;
private String serviceId;
}
@Data
@JsonRootName("core")
public static class Core extends OperationElement {
private Config config;
private String displayName;
@Data
public static class Config {
private Long a;
private Long b;
}
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Payload operationsPayload = mapper.readValue(
Files.readAllBytes(Paths.get("C:\\desc", "file.json")), Payload.class);
System.out.println(operationsPayload );
}
}
I got this error when trying to parse the json to java model:
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (FIELD_NAME), expected END_OBJECT: expected closing END_OBJECT after type information and deserialized value
line: 8, column: 7] (through reference chain: com.pojo.Payload["operations"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1799)
at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1533)
at com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer._deserialize(AsWrapperTypeDeserializer.java:124)
at com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer.deserializeTypedFromObject(AsWrapperTypeDeserializer.java:52)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:263)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:349)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:324)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:187)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3609)
If I remove
"name": "name",
"tags": "tags"
The code can run.
But I must have both these key-value in the json structure.
Any solution please suggest me. Thanks in advance.
The JsonTypeInfo.As#WRAPPER_OBJECT
works only for the serialization process while you are trying to deserialize your json input. In this case you can use the JsonTypeInfo.Id#DEDUCTION
to deduce the correct type from the existing properties. Taking for example a simplified version of your json input like below:
{
"operations": [
{
"extension": {
"serviceId": "id",
"serviceType": "type"
},
"name": "name",
"tags": "tags"
}
]
}
You have an array containing an anonymous object with the three properties extension, name, tag that can be deserialized like below:
@Data
public class Payload {
List<OperationWrapper> operations;
}
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
@JsonSubTypes.Type(value = ExtensionWrapper.class)
})
public abstract class OperationWrapper {}
@Data
public class ExtensionWrapper extends OperationWrapper {
private Extension extension;
private String name;
private String tags;
}
@Data
public class Extension {
private String serviceType;
private String serviceId;
}
Payload payload = mapper.readValue(json, Payload.class);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(payload));
Output:
{
"operations" : [ {
"extension" : {
"serviceType" : "type",
"serviceId" : "id"
},
"name" : "name",
"tags" : "tags"
} ]
}
The same mechanism can be applied to other classes you want to be deserialized.