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!!

user3364549
  • 217
  • 2
  • 4
  • 11

6 Answers6

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.

Cepr0
  • 28,144
  • 8
  • 75
  • 101
  • thanks for your answer!! but after adding the annotation as you suggested i am getting below exception in case of fetching employee details – user3364549 Mar 06 '18 at 13:06
  • org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class – user3364549 Mar 06 '18 at 13:06
  • 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 explanation – user3364549 Mar 06 '18 at 13:14
  • Thanks dude ,you save my time – Dulaj Kulathunga Oct 01 '20 at 13:53
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.

nitin verma
  • 616
  • 1
  • 6
  • 22
  • 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 Entity – Ram Apr 07 '19 at 02:05
  • Finally the answer I've been looking for :) Thank you! – Angusiasty Apr 23 '20 at 23:58
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.

Afsun Khammadli
  • 2,048
  • 4
  • 18
  • 28
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;  
}
Rajat Goel
  • 143
  • 1
  • 8
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.

sweetpoision
  • 77
  • 1
  • 8
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()  
{