派生类嵌套父类或自包含的数据模型的JSON的反序列化

派生类嵌套父类的情况,Jackson只能做到有限支持。

考虑父类:

package info.kuyur.jsondemo.models;

public class Parent {

	private String name;

	public Parent() {
		super();
	}

	public Parent(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Parent [name=" + name + "]";
	}
}

子类:

package info.kuyur.jsondemo.models;

public class Child extends Parent {

	private Integer age;
	private Parent parent;

	public Child() {
		super();
	}

	public Child(Integer age, Parent parent) {
		super();
		this.age = age;
		this.parent = parent;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Parent getParent() {
		return parent;
	}

	public void setParent(Parent parent) {
		this.parent = parent;
	}

	@Override
	public String toString() {
		return "Child [age=" + age + ", parent=" + parent + ", name="
				+ getName() + "]";
	}
}

对于json:{"age":15,"parent":{"name":"parent-name"},"name":"child-name"},能反序列化

如果构建这么一个对象:

	@Test
	public void testToJsonString3() {
		Parent grandFather = new Parent("grand-father-name");
		Child father = new Child(35, grandFather);
		father.setName("father-name");
		Child child = new Child(15, father);
		child.setName("grand-child-name");
		String jsonString = Util.toJsonString(child, Child.class);
		System.out.println(jsonString);
	}

得到的json:{"age":15,"parent":{"age":35,"parent":{"name":"grand-father-name"},"name":"father-name"},"name":"grand-child-name"},则无法反序列化,因为Jackson并不知道parent实际上应该用Child的构造函数来构建,Jackson仍然会用Parent的构造函数来构建parent,由于字段"age":35无法忽略,于是抛出异常。

非继承的自包含,比如单向链表的节点,反序列化则没有问题。

package info.kuyur.jsondemo.models;

public class LinkedNode {

	private String nodeName;
	private LinkedNode nextNode;

	public LinkedNode() {
		super();
	}

	public String getNodeName() {
		return nodeName;
	}

	public void setNodeName(String nodeName) {
		this.nodeName = nodeName;
	}

	public LinkedNode getNextNode() {
		return nextNode;
	}

	public void setNextNode(LinkedNode nextNode) {
		this.nextNode = nextNode;
	}

	@Override
	public String toString() {
		return "LinkedNode [nodeName=" + nodeName + ", nextNode=" + nextNode
				+ "]";
	}
}

json:{"nodeName":"node1","nextNode":{"nodeName":"node2","nextNode":{"nodeName":"node3","nextNode":null}}}能反序列化成功。

归结到一点,还是要为Jackson提供足够的型信息。
派生类嵌套父类会导致歧义性,Jackson只会调用基类的构造函数构建成员,所以派生类嵌套父类不是值得推荐的数据组织方法。

2012年12月19日 | 归档于 技术, 程序
  1. 2012年12月19日 19:50 | #1

    补充一下,循环引用会导致Jackson序列化堆栈溢出。

    这没问题:
    @Test
    public void testToJsonString4() {
    LinkedNode node3 = new LinkedNode();
    node3.setNodeName("node3");
    node3.setNextNode(null);

    LinkedNode node2 = new LinkedNode();
    node2.setNodeName("node2");
    node2.setNextNode(node3);

    LinkedNode node1 = new LinkedNode();
    node1.setNodeName("node1");
    node1.setNextNode(node2);

    String jsonString = Util.toJsonString(node1, LinkedNode.class);
    System.out.println(jsonString);
    }

    堆栈溢出(StackOverflowError)
    @Test
    public void testToJsonString5() {
    LinkedNode node3 = new LinkedNode();
    node3.setNodeName("node3");
    node3.setNextNode(null);

    LinkedNode node2 = new LinkedNode();
    node2.setNodeName("node2");
    node2.setNextNode(node3);

    LinkedNode node1 = new LinkedNode();
    node1.setNodeName("node1");
    node1.setNextNode(node2);

    // loop reference!
    node3.setNextNode(node1);

    String jsonString = Util.toJsonString(node1, LinkedNode.class);
    System.out.println(jsonString);
    }

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: