I am trying to write code that uses Jackson to serialize/deserialize the objects.
The objects are Polymorphic in nature:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name")
@JsonSubTypes({
@Type(value = ComparableQuery.class),
@Type(value = CompositeQuery.class)
})
public abstract class BaseQuery {
private final Long characteristicId;
...
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name")
public class CompositeQuery extends BaseQuery {
private final String operator;
private final BaseQuery[] queries;
public CompositeQuery(Long characteristicId, Operator operator, BaseQuery... queries) {
super(characteristicId);
this.operator = operator.value;
this.queries = queries;
}
...
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name")
@JsonSubTypes({
@Type(value = EqualQuery.class),
@Type(value = GreaterOrEqualQuery.class),
@Type(value = GreaterQuery.class),
@Type(value = LessOrEqualQuery.class),
@Type(value = LessQuery.class)
})
public abstract class ComparableQuery extends BaseQuery {
private final Object value;
private final String comparisonOperator;
...
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name")
public class EqualQuery extends ComparableQuery {
public EqualQuery(Long characteristicId, Object value) {
super(characteristicId, value, "=");
}
}
I have created a Set<BaseQuery> with a following code:
Set<BaseQuery> queries = new HashSet<>();
BaseQuery megapixelCharacteristicQuery = new CompositeQuery(megapixelCharacteristic.getCharacteristicId(), CompositeQuery.Operator.AND, new GreaterOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 10), new LessOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 50));
queries.add(megapixelCharacteristicQuery);
Right now when I try to serialize the object I receive a following JSON:
[
{
"characteristicId":391,
"operator":"AND",
"queries":[
{
"name":"GreaterOrEqualQuery",
"characteristicId":391,
"value":10,
"comparisonOperator":">="
},
{
"name":"LessOrEqualQuery",
"characteristicId":391,
"value":50,
"comparisonOperator":"<="
}
]
}
]
but when I try to deserialize the JSON document I'm receiving the following exception:
com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'name' that is to contain type id (for class com.example.decision.query.characteristic.BaseQuery)
at [Source: [{"characteristicId":391,"operator":"AND","queries":[{"name":"GreaterOrEqualQuery","characteristicId":391,"value":10,"comparisonOperator":">="},{"name":"LessOrEqualQuery","characteristicId":391,"value":50,"comparisonOperator":"<="}]}]; line: 1, column: 233] (through reference chain: java.util.HashSet[0])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:261)
For a some reason the name field is absent in the JSON root object.
How to fix it ?
UPDATED
It is working fine when I try to serialize only for example megapixelCharacteristicQuery object:
BaseQuery megapixelCharacteristicQuery = new CompositeQuery(megapixelCharacteristic.getCharacteristicId(), CompositeQuery.Operator.AND, new GreaterOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 10), new LessOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 50));
In this case Jackson forms the following JSON(with a correct "name":"CompositeQuery"):
{
"name":"CompositeQuery",
"characteristicId":391,
"operator":"AND",
"queries":[
{
"name":"GreaterOrEqualQuery",
"characteristicId":391,
"value":10,
"operator":">="
},
{
"name":"LessOrEqualQuery",
"characteristicId":391,
"value":50,
"operator":"<="
}
]
}
but serialization/deserialization still doesn't work when megapixelCharacteristicQuery is placed inside of HashSet<BaseQuery>.
How to make it work with HashSet ?
Also, it is start working fine even with a HashSet when I add defaultImpl = CompositeQuery.class to JsonTypeInfo annotation, for example:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name", defaultImpl = CompositeQuery.class)
@JsonSubTypes({
@Type(value = ComparableQuery.class),
@Type(value = CompositeQuery.class)
})
public abstract class BaseQuery {
...
}
but it is not an option to me because I don't know what type should be used in different cases so I'm still look for a solution how to correctly provide name parameter in my JSON.
CompositeQueryobject and right now I don't understand why.. - alexanoid@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name")annotation should automatically add one extra fieldnameto the serialized object as it has been done for example for nestedGreaterOrEqualQueryobject(please see the JSON in my question).. but this property is absent for a some unknown reason for the his owner -CompositeQuery- alexanoid