I am using Hibernate 5.2.7.Final, and native Hibernate API. I have an Employee entity with recursive relations:
@Entity
public class Employee {
@Id
@GeneratedValue
private Long employeeId;
@Column
private String firstname;
@Column
private String lastname;
@ManyToOne(cascade={ CascadeType.ALL})
@JoinColumn(name="manager_id")
private Employee manager;
@OneToMany(mappedBy="manager", cascade = CascadeType.ALL)
private Set<Employee> subordinates = new HashSet<Employee>();
// setters, getters, constructors
}
The following table is created by hibernate:
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| employeeId | bigint(20) | NO | PRI | NULL | |
| firstname | varchar(255) | YES | | NULL | |
| lastname | varchar(255) | YES | | NULL | |
| manager_id | bigint(20) | YES | MUL | NULL | |
+------------+--------------+------+-----+---------+-------+
I persists successfully the manager and the employees with:
Employee manager = new Employee("A", "B");
Employee employee1 = new Employee("C", "D");
Employee employee2 = new Employee("E", "E");
employee1.setManager(manager1);
employee2.setManager(manager1);
Set<Employee> employees = new HashSet<>();
employees.add(employee1);
employees.add(employee2);
manager.setSubordinates(employees);
session.save(manager);
Now retrieving the employee will cause StackOverFlowError.
Long id = manager.getEmployeeId();
Query<Employee> query = ss.createQuery("from Employee e where e.employeeId = :employeeId", Employee.class);
query.setParameter("employeeId", id);
Employee retrieved = (Employee) query.uniqueResult();
Exception in thread "main" java.lang.StackOverflowError
at java.lang.Long.toString(Long.java:396)
at java.lang.Long.toString(Long.java:1032)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at objectModels.Employee.toString(Employee.java:82)
at java.lang.String.valueOf(String.java:2994)
I think the way I can persist such Employee object graph is so convenient. But I have no idea how to retrieve such graph from the table.
Question: how can I meaningfully retrieve Employee information from the underlying table. I think the way around it is to create a new Entity for viewing the Employee table like
public class EmployeeView {
private Long employeeId;
private String firstname;
private String manager_name;
private Set<String> subordinate_names;
}
Can I achieve this? and how with JPA annotation?
I suspect the problem is the
toString()
method in yourEmployee
entity.Since you didn't provide any code, here is a clear example of how this would happen between a more generalized perspective of a
Parent
andChild
.Now somewhere in the code there is this:
This would cause the same overflow problem because the call into
Parent
would delegate down intoChild
which delegates back toParent
and the nasty cycle continues.You need to decide which makes the most logical sense in your case and likely either skip or only print the identifier of the associated entity to avoid this recursive loop.