【问题标题】:Jackson serialization and nexpected token (END_OBJECT), expected FIELD_NAME: missing property 'name'Jackson 序列化和预期令牌 (END_OBJECT),预期 FIELD_NAME:缺少属性“名称”
【发布时间】:2017-05-09 04:10:06
【问题描述】:

我正在尝试编写使用 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)

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

如何解决?

更新

当我尝试仅序列化 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&lt;BaseQuery&gt; 中时,序列化/反序列化仍然不起作用。

如何使它与 HashSet 一起工作?

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

@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 参数的解决方案。

【问题讨论】:

  • 您是否检查过您尝试序列化的对象上是否设置了名称?
  • 从我的问题可以看出,name字段只设置在嵌套对象上
  • 但是由于某种原因,没有为CompositeQuery 对象设置名称字段,现在我不明白为什么..
  • 如果没有在 Java 对象上设置,Jackson 不会在 JSON 中序列化该字段。 Jackson 将尝试通过将所有属性默认为强制反序列化,除非使用 @JsonInclude(JsonInclude.Include.NON_EMPTY) 注释标记,其中不会通过此异常。
  • @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name") 注释应该自动向序列化对象添加一个额外的字段name,例如嵌套GreaterOrEqualQuery 对象(请参阅我的问题中的JSON)。但是由于他的所有者的一些未知原因,此属性不存在 - CompositeQuery

标签: java json serialization jackson


【解决方案1】:

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

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

成功了。现在一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-06
    • 2011-09-20
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    相关资源
    最近更新 更多