递归到JSON的对象

时间:2014-09-15 11:58:01

标签: java json recursion

假设我有以下代码:

public class A {
    B b;

    public A() {
        this.b = new B(this);
    }
}

public class B {
    A a;

    B(A a) {
        this.a = a;
    }

}

正如您所看到的,这些对象(AB)是指彼此,如果您尝试将对象转换为JSON代码,则会导致无限递归:A具有B,其中相同的A,具有相同的B等,等等。

但是如果我尝试将这些对象转换为JSON,例如使用Gson,由于递归(顺便说一句,完全合乎逻辑),StackOverflowError会引发。

现在有一种方法可以在JSON中声明这样的递归吗?如果没有,那么有没有办法在JSON中处理这种递归?

或者我是否必须手动检查递归,删除它,将对象转换为JSON,并在将JSON字符串重建为Java对象时重新应用递归?

3 个答案:

答案 0 :(得分:3)

杰克逊有一些方法来处理循环或双向依赖,特别是两个。

如果您必须将您的实体暴露给外界,我建议在导致循环引用的属性上添加@JsonIgnore。这将告诉杰克逊不要序列化该属性。但是,这意味着您必须在反序列化时再次自己引用它们(并且在序列化时,您必须向JSON数据结构添加一些内容以了解在反序列化时再次引用的内容)。

另一种方式,我怀疑这更符合你的喜好,就是使用Jackson提供的双向功能。您可以使用@JsonManagedReference@JsonBackReference@JsonManagedReference是属性的“前向”部分,它将正常序列化。 @JsonBackReference是参考文献的“后退”部分;它不会被序列化,但会在“转发”类型被反序列化时重建。

您可以查看示例here

下面我将展示其中一个应该澄清一些事情的例子

public class NodeList {
    @JsonManagedReference
    public List<NodeForList> nodes; //this one gets serialized
}

public class NodeForList {
    public String name;

    @JsonBackReference 
    public NodeList parent; //this one wont get serialized, but will be reconstructed upon deserialization

    public NodeForList() { this(null); }
    public NodeForList(String n) { name = n; }
}

答案 1 :(得分:1)

虽然JSON与JavaScript的文字对象表示法非常相似,但它们并不完全相同。这种差异很重要。

JavaScript在内存中有一个引用的概念:许多变量都可以指向同一个对象。实际上,对于某些数据类型,它直接被烘焙到type本身:相同值的所有变量,如果该值是这些类型之一,则指向同一个点。 StringBoolean以这种方式工作。从技术上讲,Nullundefined也是如此,尽管这一点没有实际意义,因为无论如何每种类型只有一个可能的值。

尽管引用未被引入类型,但变量仍然可以引用内存中的同一对象。

相比之下,JSON没有引用概念。一切都是一个新的和独特的价值,没有两件事可以指向同一个地方。 JSON解析器和JavaScript的eval一样,都提到了这种差异(尽管你不应该使用带有JSON的eval);当每个值被读入内存时,它被转换为适当类型的变量,如果这是一个类型,其中所有相同值的变量指向同一个点,那么它们就会这样做。

但这只适用于引用被引入类型的情况; JSON没有办法指定变量,因此JSON文件中可以引用不同点的任何点,指的是不同的点。 这意味着您无法在JSON文件中执行递归。

相反,正如您所说,您的JSON生成器需要检查递归并将其删除,将其替换为某种注意,此值应引用其他内容。你如何编码这些笔记取决于你;有很多方法可以做到这一点,有些方法可以更好地满足您的应用程序的特定需求。无论如何,无论如何,你的另一端的JSON解析器需要查找这些注释并将它们转换回递归引用。

另一种方法是使用一些其他格式,它具有一些原生编码引用的方法。

答案 2 :(得分:0)

如果您只想转换为Json然后返回,则可以使用带有@JsonIdentityInfo注释的Jackson。它不会试图存储对象本身,而是存储引用。

请参阅此处了解对象标识处理:http://wiki.fasterxml.com/JacksonFeatureObjectIdentity