how to Fix spring boot one to many bidirectional infinity loop?
Asked Answered
M

6

6

i am try to create a one to many bidirectional mapping using spring boot and spring data jpa please look the below entity

Employer Entity

@Entity  
public class Employer  
{  
private Long id;  
private String employerName;  
private List<Employee> employees;  

@Id  
@GeneratedValue(strategy=GenerationType.AUTO)  
public Long getId()  
{  
    return id;  
}  
public void setId(Long id)  
{  
    this.id = id;  
}  
public String getEmployerName()  
{  
    return employerName;  
}  
public void setEmployerName(String employerName)  
{  
    this.employerName = employerName;  
}  

@OneToMany(cascade=CascadeType.ALL, mappedBy="employer")  
public List<Employee> getEmployees()  
{  
    return employees;  
}  
public void setEmployees(List<Employee> employees)  
{  
    this.employees = employees;  
}  
} 

Employee Entity

@Entity  
public class Employee  
{  
private Long id;  
private String employeeName;  
private Employer employer;  

@Id  
@GeneratedValue(strategy=GenerationType.AUTO)  
public Long getId()  
{  
    return id;  
}  
public void setId(Long id)  
{  
    this.id = id;  
}  
public String getEmployeeName()  
{  
    return employeeName;  
}  
public void setEmployeeName(String employeeName)  
{  
    this.employeeName = employeeName;  
}  
@ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)  
public Employer getEmployer()  
{  
    return employer;  
}  
public void setEmployer(Employer employer)  
{  
    this.employer = employer;  
}  
}  

Employer Repo

public interface EmployerServices extends JpaRepository<Employer, Long> {
}

Employee Repo

public interface EmployeeServices extends JpaRepository<Employee, Long> {
}

REST Controller is

 @RestController
 public class Controller {
 @Autowired EmployeeServices employeeServices;
 @Autowired EmployerServices employerServices;
 @GetMapping("/getempr")
 public Object getempr(){
    return employerServices.findOne(1L);
 }
}

now the problem begin start see my out put enter image description here

its look like a infighting loop and my server throwing error getOutputStream() has already been called for this response.

 I used @JsonBackReference & @JsonManagedReference 

annotation but the problem is its working like one to many

 {
   "id":1,
   "employerName":"employer",
   "employees":[
     {"id":1,"employeeName":"emp1"},
     {"id":2,"employeeName":"emp2"}
   ]
}  

if I am trying to get in the concern of many to one like all employee with employer. the output is

 [
  {
   "id":1,
   "employeeName":"emp1"
  },
  {
    "id":2,
    "employeeName":"emp2"}
 ]

its not showing me the employer details.

please suggets me guys what i am doing wrong. thanks in advance!!

Mandrel answered 6/3, 2018 at 11:51 Comment(0)
M
6

with the JSON its a problem with bi-directional mapping. Use the below properties.

@JsonIgnoreProperties("employer")
@JsonIgnoreProperties("employees")

please keep fetching type as eager.

hope this will work.

Maximamaximal answered 24/4, 2018 at 11:37 Comment(2)
above suggestion works along as you **don't want ** employee details appear in **employer ** json response. to appear employee details, don't use below line(above 1st line) @JsonIgnoreProperties("employer") in Employer EntityDummy
Finally the answer I've been looking for :) Thank you!Hydrodynamic
C
10

Instead of using @JsonBackReferenceand @JsonManagedReference try to use annotation @JsonIgnoreProperties:

@JsonIgnoreProperties("employer")
private List<Employee> employees;  

@JsonIgnoreProperties("employees")
private Employer employer;  

It prevents Jackson from rendering a specified properties of associated objects.

Cydnus answered 6/3, 2018 at 12:17 Comment(4)
thanks for your answer!! but after adding the annotation as you suggested i am getting below exception in case of fetching employee detailsMandrel
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for classMandrel
thanks man I got the issue it was related to lazy fetch!! could you please explain what was the problem with (@JsonBackReferenceand, @JsonManagedReference ) and how its fix with (@JsonIgnoreProperties). please give some more explanationMandrel
Thanks dude ,you save my timeSorry
M
6

with the JSON its a problem with bi-directional mapping. Use the below properties.

@JsonIgnoreProperties("employer")
@JsonIgnoreProperties("employees")

please keep fetching type as eager.

hope this will work.

Maximamaximal answered 24/4, 2018 at 11:37 Comment(2)
above suggestion works along as you **don't want ** employee details appear in **employer ** json response. to appear employee details, don't use below line(above 1st line) @JsonIgnoreProperties("employer") in Employer EntityDummy
Finally the answer I've been looking for :) Thank you!Hydrodynamic
C
0

You can solve your issue with two modification with annotations.
Employer.class

@Entity
public class Employer {
    private Long id;
    private String employerName;

    @OneToMany(cascade = CascadeType.ALL,
            mappedBy = "employer",
            orphanRemoval = true)
    private List<Employee> employees;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmployerName() {
        return employerName;
    }

    public void setEmployerName(String employerName) {
        this.employerName = employerName;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }
}


Employee.class

@Entity
public class Employee {
    private Long id;
    private String employeeName;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "employer_id")
    private Employer employer;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmployeeName() {
        return employeeName;
    }

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }

    public Employer getEmployer() {
        return employer;
    }

    public void setEmployer(Employer employer) {
        this.employer = employer;
    }
}

For more information please visit this link.

Crenulate answered 6/3, 2018 at 13:22 Comment(0)
W
0

Change your getEmployer Method like this:

@ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public Employer getEmployer()  
{  
    return employer;  
}
Wolff answered 8/6, 2021 at 13:38 Comment(0)
O
0

use

@JsonProperty(access = Access.WRITE_ONLY)
private List<Employee> employees;

So that it will ignore employees while printing to JSON in the response (and thus prevents the looping), but will still consider the JSON data (employee list) you pass in the request body so that it is available for persistence.

Olmstead answered 2/8, 2021 at 8:32 Comment(0)
P
0

I solved the issue by using @JsonManagedReference and @JsonBackReference json properties. So please change your code like as follows:

@ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)  
@JsonManagedReference
public Employer getEmployer()  

@OneToMany(cascade=CascadeType.ALL, mappedBy="employer")  
@JsonBackReference
public List<Employee> getEmployees()  
{ 
Potter answered 30/3, 2023 at 6:56 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.