关于java:Jackson JSON序列化,通过级别定义的递归避免

Jackson JSON serialization, recursion avoidance by level defining

我使用Jackson库将我的pojo对象序列化为JSON表示。例如,我有A级和B级:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
  private int id;
  private B b;

  constructors...
  getters and setters
}

class B {
  private int ind;
  private A a;

  constructors...
  getters and setters
}

如果我想从类A序列化对象,那么在序列化对象时,有一定的可能性得到递归。我知道我可以通过使用@JsonIgnore来阻止它。

是否可以按深度级别限制序列化?

例如,如果级别为2,则序列化将按以下方式进行:

  • 序列化A,级别=0(0<2 OK)->序列化
  • 序列化A.B,级别=1(1<2正常)->序列化
  • 序列化a.b.a,级别=2(2<2不正确)->停止

事先谢谢。


我最近遇到了一个类似的问题:Jackson——具有双向关系的实体的序列化(避免循环)

因此,解决方案是升级到Jackson 2.0,并将以下注释添加到类中:

1
2
3
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class,
                  property ="@id")
public class SomeEntityClass ...

这很管用。


检查以下链接,可能会有所帮助:

  • http://wiki.fasterxml.com/jacksonfeaturebidisreferences
  • 如何解决由Hibernate双向映射引起的JSON序列化程序中的循环引用问题?

之后的唯一选项是为对象类型创建自己的自定义模块,用于序列化/反序列化。请参见此处:

  • http://wiki.fasterxml.com/jacksonhowtocustomerializer
  • http://wiki.fasterxml.com/jacksonhowtocustomdeserializer

当做。


不支持基于级别的忽略。

但是您可以让Jackson使用2.0处理循环引用,请参见例如"Jackson 2.0 released"以了解如何使用@JsonIdentityInfo


如果您只想将自己限制在一个级别(即:转到当前对象的子级,而不是更进一步),那么@jsonview有一个简单的解决方案。

在每个链接到另一个对象的字段上,用当前类作为视图对其进行注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
  private int id;
  @JsonView(A.class) private B b;

  constructors...
  getters and setters
}

class B {
  private int ind;
  @JsonView(B.class) private A a;

  constructors...
  getters and setters
}

然后,在序列化时,使用对象类作为视图。序列化的实例将呈现如下情况:

1
2
3
4
5
6
{
  id: 42,
  b: {
    id: 813
  }
}

确保默认的_view_inclusion设置为true,否则将不会呈现没有@jsonview注释的字段。或者,您可以使用对象类或任何常见的超级类,用@jsonview注释所有其他字段:

1
2
3
4
5
6
7
class A {
  @JsonView(Object.class) private int id;
  @JsonView(A.class) private B b;

  constructors...
  getters and setters
}


有关深度序列化,请参阅以下示例:https://github.com/abid-khan/depth-wise-json-serializer


经过几个月和大量的研究,我已经实现了自己的解决方案,以使我的领域远离杰克逊的依赖性。

1
2
3
4
5
6
7
8
9
10
11
public class Parent {
    private Child child;
    public Child getChild(){return child;}
    public void setChild(Child child){this.child=child;}
}

public class Child {
    private Parent parent;
    public Child getParent(){return parent;}
    public void setParent(Parent parent){this.parent=parent;}
}

首先,您必须以如下方式声明双向关系的每个实体:

1
2
3
4
5
6
7
8
9
public interface BidirectionalDefinition {

    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=Parent.class)
    public interface ParentDef{};

    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=Child.class)
    public interface ChildDef{};

}

之后,可以自动配置对象映射器:

1
2
3
4
5
ObjectMapper om = new ObjectMapper();
Class<?>[] definitions = BidirectionalDefinition.class.getDeclaredClasses();
for (Class<?> definition : definitions) {
    om.addMixInAnnotations(definition.getAnnotation(JsonIdentityInfo.class).scope(), definition);
}


在某些情况下,可以使用保持最大深度的线程局部整数来限制序列化深度。看看这个答案。