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.