Jackson - Serialization of Entities with Birectional Relationships (Avoiding Cycles)

Jackson - serialization of entities with birectional relationships (avoiding cycles)

Jackson 2.0 does support full cyclic object references. See "Jackson 2.0 released" (section 'Handle Any Object Graphs, even Cyclic ones!') for an example.

Basically, you will need to use new @JsonIdentityInfo for types that require id/idref style handling. In your case this would be both Parent and Child types (if one extends the other, just add it to super type and that's fine).

Jackson JSON serialization, recursion avoidance by level defining

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.

Infinite Recursion with Jackson JSON and Hibernate JPA issue

You may use @JsonIgnore to break the cycle (reference).

You need to import org.codehaus.jackson.annotate.JsonIgnore (legacy versions) or com.fasterxml.jackson.annotation.JsonIgnore (current versions).

Cyclic references in a bidirectional many to many relationship

I ended up implementing the following solution.

One end of the relationship is considered to be the parent. It does not need any Jackson related annotation.

public class Collaboration {

private Set<Tag> tags;

}

The other side of the relationship is implemented as follows.

public class Tag {

@JsonSerialize(using = SimpleCollaborationSerializer.class)
private Set<Collaboration> collaborations;

}

I'm using a custom serializer to will make sure that no cyclic references will occur. The serializer could be implemented like this:

public class SimpleCollaborationSerializer extends JsonSerializer<Set<Collaboration>> {

@Override
public void serialize(final Set<Collaboration> collaborations, final JsonGenerator generator,
final SerializerProvider provider) throws IOException, JsonProcessingException {
final Set<SimpleCollaboration> simpleCollaborations = Sets.newHashSet();
for (final Collaboration collaboration : collaborations) {
simpleCollaborations.add(new SimpleCollaboration(collaboration.getId(), collaboration.getName()));
}
generator.writeObject(simpleCollaborations);
}

static class SimpleCollaboration {

private Long id;

private String name;

// constructors, getters/setters

}

}

This serializer will only show a limited set of the properties of the Collaboration entity. Because the "tags" property is omited, no cyclic references will occur.

A good read about this topic can be found here. It explains all possibilities when you're having a similar scenario.

Losing the child data in a bi-directional relationship when using jacksonMapper

I have not been able to find out why this is happening. Meanwhile I have opted for a workaround. I am making two separate calls to DB. One to fetch the parent first and then second to fetch the child based on the fetched parentId.

Alternatively, I can make both the DB calls at the service same time and prepare the JSON as a complex string before sending it to the ui:

complex:{
parent:parent,
child:child
}

In either case, it is a workaround. The ideal solution is just remove@JsonIgnore in the mapping only from the parent side for the child class. But somehow that doesn't seem to work. I'll post in case I find why the "ideal" solution is not working!

Ideal Solution Updated as answer on 15 Aug 2016 The Independence Day of India:

The problem is in the mapping:

Parent implements Serializable{

@ManytoMany(//declaration for join table)
@JsonBackReference
@com.fasterxml.jackson.annotation.JsonIgnore
Set <Child> childSet;

}

When you say @JsonBackReference it actually means ignore this field while writing the Json, i.e. to say,

@JsonBackReference <-> @JsonIgnore

Hence the child is omitted when the parent is serialized. With ORM mappings it's always a best practice to have the annotations one sided rather than double sided. In that way, you can avoid a lot of unwanted exceptions while fetching the data and secondly, keep your business code clean.

JsonManagedReference vs JsonBackReference

Infinite recursion with Jackson on intermediate table

When unhandled bidirectional relationship occurs, Jackson faces infinite recursion.

I tried to use @JsonIgnore, @JsonManagedReference and @JsonBackReference on the Written class

You need to use @JsonManagedReference and @JsonBackReference annotations separately to prevent these cycles between Book and Written. A side note, transient has nothing to do with the persistence but the serialization. JPA works with the @Transient annotation.

public class Book implements Serializable {

@OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
@JsonBackReference
private Set<Written> written= new HashSet<>();

...
}
public class Written implements Serializable {

@Id
@ManyToOne
@JoinColumn(name = "idBook")
@JsonManagedReference
private Book book;

...
}

Important: Don't send database entities through REST (probably what you are up to do). Better create a DAO object without bidirectional relationship and map entities into DAOs. There are several libraries able to do that: I highly recommend MapStruct, however ModelMapper is also an option. If there is a lower number of such entities, using constructors/getters/setters would be enough.

Jackson bidirectional relationship (One-to-many) not working

Because you are using the @JsonBackReference on the Customer property in the Loan entity, the Customer object will not included in the serialization. Use the @JsonManagedReference for the Customer in the Loan object and use @JsonBackReference on the Loan property in the Customer entity.

This will serialize the Customer property of your Loan entity. But the Customer object serialization will not contains the Loan property. You need to pick one side of the relationship to serialize.

To allow both side, use @JsonIdentityInfo annotation in your entity and remove the @JsonBackReference and @JsonManagedReference. You entities will be something like:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "customerId")
public class Customer implements Serializable {
...
}

The property of the @JsonIdentityInfo refer to your entity id property, for Customer this will be customerId. Do this for Loan and Item also.



Related Topics



Leave a reply



Submit