我使用Jackson来序列化JSON,但我的JSON客户端不是Java,也不使用Jackson。
我想避免循环引用序列化无限递归,每当序列化整个bean会导致无限递归时,序列化bean的id而不是整个bean。
这可以通过维护当前序列化上下文的堆栈来实现。
每当Jackson开始序列化bean时,它应该看看堆栈是否包含bean。
如果bean已经在堆栈中,则序列化id而不是整个bean,从而避免无限递归。
如果bean不在堆栈中,则将其推入堆栈,并正常序列化整个bean。
杰克逊完成序列化bean后,将bean从堆栈中弹出。
因此,我希望以下Java序列化为以下JSON:
爪哇:
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"
}
}
我只知道两种内置的Jackson处理循环引用的方法,如果我理解正确的话,它们都不能输出上面的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
}
是否有任何内置的杰克逊方式按照我的要求进行序列化?
如果没有,杰克逊是否会保留序列化堆栈?
如果是这样,我该如何访问它,并以某种方式修改序列化输出?
如果没有,我如何挂钩杰克逊来维护我自己的类中的堆栈,这些类实现了一些Jackson接口/扩展了一些Jackson类,然后使用该堆栈来影响序列化?
答案 0 :(得分:1)
杰克逊确实保留了几个筹码。较旧的版本处于JsonGenerator
级别,请参阅getOuputContext()
。这可以让你看到物理输出的内容,即哪个范围(对象,数组)是开放的。
但Jackson 2.5添加了新的方法JsonGenerator.getCurrentValue()
,以及来自数据绑定的匹配调用,它还应该为您提供序列化的对象图形视图,至少在组合两者时。
要访问当前值的祖先,您需要遍历"输出上下文",向输出堆栈请求当前值。