To solve the problem, there are general two ways according to the Jackson documentation.
Approach 1
Before Jackson 2.0, handling of cyclic object graphs was limited to specific case of parent/child(bi-directional) references. Using @JsonManagedReference and @JsonBackReference
Add the @JsonManagedReference in the forward part of the relationship which you want to serialize, and add in the back part of the relationship which will not be serialized. See the following example that Material and Supplier is @ManyToMany relationship.
@Entity
public class Material{
...
@JsonManagedReference
private List<Supplier> costSuppliers = new ArrayList<>();
...
}
@Entity
public class Supplier{
...
@JsonBackReference
private List<Material> costMaterials = new ArrayList<>();
....
}
If we serialize a Material instance to JSON, we will get an Array containing Supplier instances, but the drawback of this approach is that, when we serialize a Supplier instance to JSON, we will not get the Material array instance.
Approach 2
Jackson 2 provides a new annotation @JsonIdentityInfo which is used for indicating that values of annotated type or property should be serializing so that instances either contain additional object identifier, or as a reference that consists of an object id that refers to a full serialization. For the last example will be someting like this:
@Entity
public class Material{
...
private List<Supplier> costSuppliers = new ArrayList<>();
...
}
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Supplier{...
private List<Material> costMaterials = new ArrayList<>();
....
}
Thus the cyclic dependency and Stackoverflow issue could be solved. But the drawback is that, just as the Jackson documentation says:
"In practice this is done by serializing the first instance as full object and object identity, and other references to the object as reference values."
It means that, say, we serialized a Material object which has an Supplier array, however, only the first element of the array is Supplier object, the rest elements in the array is not Supplier object but Supplier reference (general the id). This not what a want, cause generally I want to render the whole properties of the Supplier object, but I need to request the Supplier info again with its reference :(
Approach 3
Forget @JsonManagedReference, @JsonBackReference, and @JsonIdentityInfo, we just use the simple @JsonIgnoreProperties, see below:
@Entity
public class Material{
...
@JsonIgnoreProperties("costMaterials")
private List<Supplier> costSuppliers = new ArrayList<>();...
}
@Entity
public class Supplier{
...
@JsonIgnoreProperties("costSuppliers")
private List<Material> costMaterials = new ArrayList<>();....
}
Simple annotation and simple use, NO infinite recursive Stackoverflow and get all the "Object" information in the serialized JSON :)