【问题标题】:How to deserialize JSON having references to abstract types in Jackson如何反序列化具有对 Jackson 中抽象类型的引用的 JSON
【发布时间】:2017-06-27 20:22:41
【问题描述】:

我对抽象类的对象引用以及 JSON 序列化和反序列化有疑问。抽象的问题如下所示:

我有一个由节点和边组成的图。每条边连接两个节点。节点可以是红色和绿色的味道。因此,有一个抽象类Node 和两个派生类RedNodeGreenNodeNode 需要 id (@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")):

@JsonSubTypes({
    @JsonSubTypes.Type(value = GreenNode.class, name = "GreenNode"),
    @JsonSubTypes.Type(value = RedNode.class, name = "RedNode")
})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public abstract class Node {
    public String id;
}

public class RedNode extends Node {
    // ...
}

public class GreenNode extends Node {
    // ...
}

Edge 具有 Node 类型的源和目标,它们被序列化为引用 (@JsonIdentityReference(alwaysAsId = true)):

public class Edge {
    @JsonIdentityReference(alwaysAsId = true)
    public Node source;
    @JsonIdentityReference(alwaysAsId = true)
    public Node target;
}

图形定义如下:

public class Graph {
    public List<GreenNode> greenNodes = new ArrayList();
    public List<RedNode> redNodes = new ArrayList();
    public List<Edge> edges = new ArrayList();
}

一个示例 JSON 如下所示:

{
  "greenNodes" : [ {
    "id" : "g",
    "content" : "green g",
    "greenProperty" : "green"
  } ],
  "redNodes" : [ {
    "id" : "r",
    "content" : "red r",
    "redProperty" : "red"    
  } ],
  "edges" : [ {
    "source" : "g",
    "target" : "r"
  } ]
}

使用ObjectMapper 无法读取此内容:

无法构造 com.github.koppor.jsonidentityissue.model.Node 的实例:抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,要么包含额外的类型信息

错误位置是“第 13 行,第 16 列”。因此,它在边缘的 id 处被击中。节点本身已正确序列化。

一种解决方法是在 json 中添加类型信息:

@JsonTypeInfo(
      use = JsonTypeInfo.Id.NAME,
      include = JsonTypeInfo.As.PROPERTY,
      property = "type")
public abstract class Node {

然后,一切正常:

{
  "greenNodes" : [ {
    "id" : "g",
    "type" : "GreenNode",
    "content" : "green g",
    "greenProperty" : "green"
  } ],
  "redNodes" : [ {
    "id" : "r",
    "type" : "RedNode",
    "content" : "red r",
    "redProperty" : "red"    
  } ],
  "edges" : [ {
    "source" : "g",
    "target" : "r"
  } ]
}

然后,一切正常。

真的有必要在引用对象中包含类型信息以使引用工作吗?如果没有类型信息,则可以加载具有红色和绿色节点(并且没有边)的图形。边缘进来后,它不能。但是,一条边的 JSON 只包含一个 id。引用的对象已被解析。

我真的很想摆脱@JsonTypeInfo 注释。有没有办法获得干净的 JSON?

完整示例可在https://github.com/koppor/jackson-jsonidentityreference-issue/tree/issue 获得。

【问题讨论】:

    标签: jackson


    【解决方案1】:

    当前的解决方案是包含虚假类型信息。完整代码https://github.com/koppor/jackson-jsonidentityreference-issue

    Node 得到一个现有的属性type,没有写出来:

    @JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "type")
    public abstract class Node {
        @JsonIgnore
        public abstract String getType();
    }
    

    每个子类都将自己指定为defaultImpl,并提供getType的实现:

    @JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "type",
        defaultImpl=GreenNode.class)
    public class GreenNode extends Node {
        @Override
        public String getType() {
            return "GreeNode";
        }
    }
    

    这样,JSON 保持干净,但 Jackson 可以毫无问题地解析 id 引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-06
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多