35

I use Jackson library for serialization of my pojo objects into JSON representation. For example I have class A and class B:

class A {
  private int id;
  private B b;

  constructors...
  getters and setters
}

class B {
  private int ind;
  private A a;

  constructors...
  getters and setters
}

If I want to serialize object from class A there is certain possibility to get recursion while it is serialized. I know i can stop it by using @JsonIgnore.

Is it possible to limit the serialization by depth-level ?

For example, if the level is 2, the serialization will go this way:

  • serialize a, level = 0 (0 < 2 ok) - > serialize
  • serialize a.b, level =1 (1 < 2 ok) -> serialize
  • serialize a.b.a, level = 2 (2 < 2 not true) -> stop

Thanks in advance.

Goran Nastov
  • 995
  • 1
  • 9
  • 17
  • Were you able to find a way finally to specify the recursion depth that for which you wanted the serialization to happen? – Eric B. Dec 21 '13 at 05:47
  • I solved by using @JsonIgnore on the referenced entities(with recursion), so simply I don't include into the serialization. When I need the specific instance I already have the ID and I make additional call to get the instance. I did not used a general solution, luckily I have few cases. – Goran Nastov Dec 25 '13 at 13:23

7 Answers7

27

I recently encountered a similar problem: Jackson - serialization of entities with birectional relationships (avoiding cycles)

So the solution is to upgrade to Jackson 2.0, and add to classes the following annotation:

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

This works perfectly.

Community
  • 1
  • 1
Eugene Retunsky
  • 13,009
  • 4
  • 52
  • 55
  • 10
    this is really nice way. but do you know a way of limiting the deepness of the graph? – oak Jan 06 '14 at 09:49
  • 1
    Nice, thanks. Note: the default value of property is "@id", so it could be omitted here (see source of JsonIdentityInfo => String property() default "@id";) – Jos Mar 05 '20 at 09:57
13

Check the following links, it might help :

The only option after that would be to create your own custom module for serialization/deserialisation for your object type. see here:

Regards.

Community
  • 1
  • 1
Farid
  • 2,265
  • 18
  • 14
4

There is no support for level-based ignorals.

But you can get Jackson to handle cyclic references with 2.0, see for example "Jackson 2.0 released" for explanation on how to use @JsonIdentityInfo.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • can you give some pointers here. Thanks. https://stackoverflow.com/questions/53824858/writing-custom-serializers-and-deseralizers-recursive-implementations – brain storm Dec 18 '18 at 07:58
3

If you want to limit yourself to only one level (ie : you go to the children of the current object and not further), there is a simple solution with @JsonView.

On every field that is a link to another object, annotate it with the current class as your view :

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
}

Then, when serializing, use the object class as your view. Serializing an instance of A would render something like that :

{
  id: 42,
  b: {
    id: 813
  }
}

Make sure the DEFAULT_VIEW_INCLUSION is set to true, or the fields without a @JsonView annotation will not be rendered. Alternatively, you can annotate all other fields with @JsonView using the Object class, or any common super-class :

class A {
  @JsonView(Object.class) private int id;
  @JsonView(A.class) private B b;

  constructors...
  getters and setters
}
2

For depth wise serialization, you can refer to example here https://github.com/abid-khan/depth-wise-json-serializer

Abid
  • 101
  • 1
  • 1
  • 4
0

For some cases you can limit serialization depth using a thread local integer holding max depth. See this answer.

Community
  • 1
  • 1
Vjeko
  • 171
  • 1
  • 3
0

After several months and a lot of research, I've implemented my own solution to keep my domain clear of jackson dependencies.

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;}
}

First, you have to declare each of your entities of the bidirectional relationship in something like this:

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{};

}

After that, the object mapper can be automatically configured:

ObjectMapper om = new ObjectMapper();
Class<?>[] definitions = BidirectionalDefinition.class.getDeclaredClasses();
for (Class<?> definition : definitions) {
    om.addMixInAnnotations(definition.getAnnotation(JsonIdentityInfo.class).scope(), definition);
}
Pablo
  • 2,430
  • 1
  • 13
  • 11