JPA: java.lang.StackOverflowError on adding toString method in entity classes
Entity Class Teacher have toString()
problem:
@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
+ "]";
}
}
You must exclude the redundant parameter from the toString() method.
- In Java using Lombok with
@ToString.Exclude
- In Kotlin using a custom annotation with
@ExcludeToString
GL
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.