我正在使用Jackson序列化JSON,但我的JSON客户端不是Java,也不使用Jackson。
我想避免循环引用序列化无限递归,每当整个豆类序列化会引起无限的递归,序列化豆的ID而不是整个豆子。
这可以通过维护当前序列化上下文的堆栈来实现。
每当杰克逊开始序列化豆时,它应该查看堆栈是否包含bean。
如果Bean已经在堆栈中,请序列化ID而不是整个Bean,从而避免了无限的递归。
如果豆不在堆栈中,请将其推到堆栈上,并正常序列化整个豆子。
杰克逊(Jackson)序列化豆子后,将豆从堆栈中弹出。
因此,我希望以下Java序列化为以下JSON:
java:
class A {
String id;
B b;
B c;
}
class B {
String id;
A a;
}
class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
a.id = "a1";
b.id = "b1";
a.b = b;
a.c = b;
b.a = a;
ObjectMapper m = new ObjectMapper();
System.out.println(m.writeValueAsString(a));
System.out.println(m.writeValueAsString(b));
}
}
json:
{
"id": "a1",
"b": {
"id": "b1",
"a": "a1"
},
"c": {
"id": "b1",
"a": "a1"
}
}
{
"id": "b1",
"a": {
"id": "a1",
"b": "b1"
}
}
我只知道两种内置杰克逊处理循环引用的方法,如果我正确理解它们,都不能输出上述JSON:
@JsonIdentityInfo
,当最好的设置时,请同时注释A
&B
with:@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
将输出(带有注释表示问题):
{ "id": "a1", "b": { "id": "b1", "a": "a1" }, "c": "b1" // problem: value of "c" is b.id instead of b with b.a = a.id } { "id": "b1", "a": { "id": "a1", "b": "b1" } }
@JsonManagedReference
&@JsonBackReference
,我必须为此指定一侧为前方,而另一侧为背部。说我选择A
->B
属性作为向前的属性,然后得到:{ "id": "a1", "b": { "id": "b1", "a": "a1" }, "c": { "id": "b1", "a": "a1" } } { "id": "b1" // problem: "a" isn't serialized }
我想要的是杰克逊的内置方式吗?
如果不是,杰克逊是否保持序列化堆栈?
如果是这样,我该如何访问它,并以某种方式修改序列化输出?
如果不是,我该如何挂接杰克逊在我自己的课堂中维护堆栈,以实现杰克逊接口/扩展一些杰克逊课程,然后使用该堆栈来影响序列化?
杰克逊确实维护了几个堆栈。较旧的是JsonGenerator
级别,请参见getOuputContext()
。这使您可以看到正在物理上输出的内容,也就是说,范围(对象,数组)是打开的。
但是杰克逊2.5添加了新方法, JsonGenerator.getCurrentValue()
和databind的匹配调用,此外,至少在组合两者时,应为您提供序列化的对象图视图。要访问当前价值的祖先,您需要遍历"输出上下文",要求当前价值提高输出堆栈。