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
Java Equivalent to #Region in C#
Selenium Webdriver: Wait for Complex Page with JavaScript to Load
Why Isn't This Code Causing a Concurrentmodificationexception
How to Define a Method Which Takes a Lambda as a Parameter in Java 8
Java.Sql.Sqlexception: Incorrect String Value: '\Xf0\X9F\X91\Xbd\Xf0\X9F...'
Java.Lang.Noclassdeffounderror: Could Not Initialize Class Xxx
Spring Crudrepository Findbyinventoryids(List<Long> Inventoryidlist) - Equivalent to in Clause
Differencebetween Getfields and Getdeclaredfields in Java Reflection
Which Annotation Should I Use: @Idclass or @Embeddedid
"Unmappable Character for Encoding" Warning in Java
How to Do If-Else in Thymeleaf
What Package Naming Convention Do You Use for Personal/Hobby Projects in Java
How to Remove a Key from Hashmap While Iterating Over It
Jpa: What Is the Proper Pattern for Iterating Over Large Result Sets