杰克逊序列化和nexpected标记(END_OBJECT),预期FIELD_NAME:缺少属性'name'

时间:2016-12-23 12:37:20

标签: java json serialization jackson

我正在尝试编写使用Jackson序列化/反序列化对象的代码。

对象本质上是多态的:

@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, "=");
    }

}

我使用以下代码创建了Set<BaseQuery>

    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);

现在,当我尝试序列化对象时,我收到了以下JSON:

[
   {
      "characteristicId":391,
      "operator":"AND",
      "queries":[
         {
            "name":"GreaterOrEqualQuery",
            "characteristicId":391,
            "value":10,
            "comparisonOperator":">="
         },
         {
            "name":"LessOrEqualQuery",
            "characteristicId":391,
            "value":50,
            "comparisonOperator":"<="
         }
      ]
   }
]

但是当我尝试反序列化JSON文档时,我收到以下异常:

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)

由于某种原因,JSON根对象中不存在name字段。

如何解决?

已更新

当我尝试仅为例如megapixelCharacteristicQuery对象序列化时,它工作正常:

BaseQuery megapixelCharacteristicQuery = new CompositeQuery(megapixelCharacteristic.getCharacteristicId(), CompositeQuery.Operator.AND, new GreaterOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 10), new LessOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 50));

在这种情况下,Jackson形成以下JSON(具有正确的"name":"CompositeQuery"):

{
   "name":"CompositeQuery",
   "characteristicId":391,
   "operator":"AND",
   "queries":[
      {
         "name":"GreaterOrEqualQuery",
         "characteristicId":391,
         "value":10,
         "operator":">="
      },
      {
         "name":"LessOrEqualQuery",
         "characteristicId":391,
         "value":50,
         "operator":"<="
      }
   ]
}

但是当megapixelCharacteristicQuery置于HashSet<BaseQuery>内时,序列化/反序列化仍然不起作用。

如何使它与HashSet一起使用?

此外,当我将HashSet添加到defaultImpl = CompositeQuery.class注释时,即使使用JsonTypeInfo,它也能正常工作,例如:

@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 {
...
}

但它不是我的选择,因为我不知道在不同的情况下应该使用什么类型,所以我仍然在寻找一个解决方案如何在我的JSON中正确提供name参数。

1 个答案:

答案 0 :(得分:2)

最后,由于以下问题Why does Jackson polymorphic serialization not work in lists?中提供的答案,我找到了一个解决方案:

Set<BaseQuery> queries = new HashSet<BaseQuery>() {
};

做了这个伎俩。现在一切都按预期工作了。