James
James

Reputation: 21

Java Hibernate json infinite recursion with self referencing class

class employee:

@Entity
@Table(name = "Employee")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "EmployeeID")
    private int EmployeeID;

    @Column(name = "ManagerID")
    private Integer ManagerID;

    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="ManagerID", insertable = false, updatable = false)
    @JsonBackReference
    private Employee manager;

    @OneToMany(mappedBy="manager")
    @JsonManagedReference
    private Set<Employee> employees;

    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name = "DepartmentID")
    private Department department;

    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name = "SalaryTypeID")
    private SalaryType salaryType;

    @Column(name = "Name")
    private String Name;
    //setters and getters here, wont be posting them
}

Whenever I create an instance of employee I get this infinite json error:

SEVERE: Servlet.service() for servlet [SpringMVC] in context with path 
[/SpringMVC] threw exception [Handler processing failed; nested exception is 
java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError
at java.nio.CharBuffer.<init>(Unknown Source)
at java.nio.HeapCharBuffer.<init>(Unknown Source)
at java.nio.CharBuffer.wrap(Unknown Source)
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.Writer.write(Unknown Source)
at com.google.gson.stream.JsonWriter.string(JsonWriter.java:534)
at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:402)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:495)

(and then it keeps going)

Since I am self referencing manager which is an employee in the employee class, how can I fix this?

Upvotes: 2

Views: 3349

Answers (2)

Peter Catalin
Peter Catalin

Reputation: 1462

I know that this question is old but just in case someone stumbles upon this.

You've put the annotations in the wrong order. Here is my example:

@Getter
@Setter
@NoArgsConstructor
public class OutboundGoodsTypeDTO extends OutboundEntityDTO {

  @JsonManagedReference
  private OutboundGoodsTypeDTO parent;

  @JsonBackReference
  private Set<OutboundGoodsTypeDTO> goodsTypes;
}

From the documentation:

@JsonManagedReference

Annotation used to indicate that annotated property is part of two-way linkage between fields; and that its role is "parent" (or "forward") link.

@JsonBackReference

Annotation used to indicate that associated property is part of two-way linkage between fields; and that its role is "child" (or "back") link.

Upvotes: 0

J-Alex
J-Alex

Reputation: 7117

There are bunch of options depends on your requirement:

1) @JsonIgnore can be used to avoid serialization of the field.

@OneToMany(mappedBy="manager")
@JsonIgnore
private Set<Employee> employees;

2) @JsonView can hide one part of the relationship as internal view (but will appear if you will write JSON object with Internal view):

@OneToMany(mappedBy="manager")
@JsonView(Views.Internal.class)
private Set<Employee> employees;

@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name = "DepartmentID")
@JsonView(Views.Public.class)
private Department department;

3) Using custom serialiazer you can determine the rules of building your JSON object yourself.

4) Using @JsonIdentityInfo on classes (to indicate that properties of that type should have feature enabled) as well as on individual properties (to support cases where type itself can not be annotated; or to use different id generation sequence).

Example 1 @JsonIdentityInfo

Example 2 @JsonIdentityInfo

Upvotes: 4

Related Questions