My API shows me infinite loop for adress field
When I insert @JsonIgnore, @JsonManagedReference or @JsonBackReference I can clearly see one result as it should be, but than i don't have nested address fields.
What should I do to have also that address fields but one result?
These are my main entities:
1.Property
package com.realestate.petfriendly.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Data
@Table(name = "property")
public class Property {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_property")
private int id_property;
@Column(name = "title")
private String title;
@Column(name = "type")
private String type;
@Column(name = "room")
private String room;
@Column(name = "price")
private double price;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "address_id_address")
// @JsonBackReference
private Address address;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id_user")
// @JsonBackReference
private User user;
}
- User
package com.realestate.petfriendly.entity;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
@Table(name = "user")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_user")
private int id_user;
@Column(name = "username")
private String username;
@Column(name = "name")
private String name;
@Column(name = "lastname")
private String lastname;
@Column(name = "phone")
private String phone;
@Column(name = "notes")
private String notes;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "user_address_id_user_address")
// @JsonManagedReference
private UserAddress userAddress;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
// @JsonManagedReference
private List<Property> property = new ArrayList<>();
}
- Address
package com.realestate.petfriendly.entity;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
@Table(name="address")
class Address{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_address")
private int id_address;
@Column(name = "city")
private String city;
@Column(name = "municipality")
private String municipality;
@Column(name = "place")
private String place;
@Column(name = "street")
private String street;
@Column(name = "house_number")
private double house_number;
@OneToOne(mappedBy = "address")
// @JsonManagedReference
private Property property;
}
CodePudding user response:
You have circular dependency between Property and Address class. In order to block infinite JSON serialization loop you can add @JsonIgnore annotation on one side of related properties
CodePudding user response:
You actually have the solution to your problem in your code, but the key annotations are commented-out and in the wrong places (according to your requirements). One of the ways to tackle this is by using @JsonManagedReference
and @JsonBackReference
as follows:
@Entity
@Data
@Table(name = "property")
public class Property {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_property")
private int id_property;
@Column(name = "title")
private String title;
@Column(name = "type")
private String type;
@Column(name = "room")
private String room;
@Column(name = "price")
private double price;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "address_id_address")
@JsonManagedReference
private Address address;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id_user")
@JsonBackReference
private User user;
}
@Entity
@Getter
@Setter
@Table(name = "user")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_user")
private int id_user;
@Column(name = "username")
private String username;
@Column(name = "name")
private String name;
@Column(name = "lastname")
private String lastname;
@Column(name = "phone")
private String phone;
@Column(name = "notes")
private String notes;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "user_address_id_user_address")
private UserAddress userAddress;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
@JsonManagedReference
private List<Property> property = new ArrayList<>();
}
@Entity
@Getter
@Setter
@Table(name="address")
class Address{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_address")
private int id_address;
@Column(name = "city")
private String city;
@Column(name = "municipality")
private String municipality;
@Column(name = "place")
private String place;
@Column(name = "street")
private String street;
@Column(name = "house_number")
private double house_number;
@OneToOne(mappedBy = "address")
@JsonBackReference
private Property property;
}
Keep in mind the following:
@JsonManagedReference
is the forward part of the relationship: the one that gets serialized normally.@JsonBackReference
is the back part of the relationship: it will be omitted from serialization.
If you want to have a reference to the back part of the relationship, you can use @JsonIdentityInfo
as follows:
@Entity
@Data
@Table(name = "property")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id_property")
public class Property {
(...)
}
@Entity
@Getter
@Setter
@Table(name = "user")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id_user")
class User {
(...)
}
@Entity
@Getter
@Setter
@Table(name="address")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id_address")
class Address{
(...)
}
You can read more about these and other techniques in the following online resource: https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.