JPA: java.lang.StackOverflowError on adding toString method in entity classes
hibernate, jpa-2.1, jpql, stack-overflow, tostring
Solution
Updated based on the addition of the Student class
According to the stack trace, your problem is associated with the `Student.toString()`, so here's what is happening:
In `Teacher.toString()`, you are implicitly calling the `Student.toString()` by placing the `students` member within a `String` concatenation statement: `+ students +`. Within `Student.toString()` the code does something similar, by including the `teacher` member within a `String` concatenation statement.
This means that calling either `Teacher.toString()` or `Student.toString()` will end up causing a never-ending loop where: `Teacher.toString()` implicitly calls `Student.toString()`, which in turn implicitly calls `Teacher.toString()`, which in turn calls `Student.toString()`, which in turn calls...
The 2 `.toString()` implementations keep calling back and forth, back and forth, back and forth, in a never-ending loop, which eventually overflows the stack and results in a `java.lang.StackOverflowError`.
To correct the problem, you should remove the implicit references to the `.toString()` methods of the entities. As a replacement, you could have `Teacher.toString()` simply output the `length()` of the `students` collection and maybe include a list of the `Student` name(s). And in the `Student.toString()`, simply include the `Teacher.name` member.
Problem
Everything worked fine until I added `toSting()` in my entity classes. After which I start getting the following error in runtime: ``` Exception in thread "main" java.lang.StackOverflowError at java.lang.AbstractStringBuilder.append(Unknown Source) at java.lang.StringBuilder.append(Unknown Source) at java.lang.StringBuilder.<init>(Unknown Source) at entity.Guide.toString(Guide.java:51) at java.lang.String.valueOf(Unknown Source) at java.lang.StringBuilder.append(Unknown Source) at entity.Student.toString(Student.java:45) ... ``` ``` @Entity public class Teacher { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String name; @OneToMany(mappedBy="teacher", cascade={CascadeType.PERSIST}) private Set<Student> students = new HashSet<Student>(); public Teacher() {} public Teacher(String name) { this.name = name; } public Set<Student> getStudents() { return students; } public void addStudent(Student student) { students.add(student); student.setTeacher(this); } @Override public String toString() { return "Teacher[id=" + id + ", name=" + name + ", students=" + students + "]"; } } ``` ``` public class SnafuClient { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("snafu"); EntityManager em = emf.createEntityManager(); EntityTransaction txn = em.getTransaction(); try { txn.begin(); Query query = em.createQuery("select teacher from Teacher teacher"); List<Teacher> teachers = query.getResultList(); for (Teacher teacher: teachers) { System.out.println(teacher); } txn.commit(); } catch(Exception e) { if(txn != null) { txn.rollback(); } e.printStackTrace(); } finally { if(em != null) { em.close(); } } } } ``` EDIT: Code for Student entity added ``` @Entity public class Student { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String name; @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}) @JoinColumn(name="teacher_id") private Teacher teacher; public Student() {} public Student(String name, Teacher teacher) { this.name = name; this.teacher = teacher; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student [id=" + id + + ", name=" + name + ", teacher=" + teacher + "]"; } } ```