Infinite recursion in a bidirectional Manytomany model in Hibernate

Asked

Viewed 207 times

0

I’m trying to create a bi-directional Manytomany relationship in Java, I can already insert into the database smoothly, but when I try to bring data from these tables I fall into an infinite recursion... I saw that this is a known error of Json in java and tried to implement the solutions in this baeldung tutorial but none of them worked, maybe I’m putting the notes in the wrong place.

*What I need is to find 1 student (Student), and all the courses(Course) in which he signed up. (in this problem itself, the teacher base(Teacher) is not involved) *

Database

enter image description here

Models

Student

@Component
@Entity
@Table(name="Student")
public class Student {

    @Id
    @Column(name="student_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @Column(name="student_name")
    private String name;

    @Column(name="student_address")
    private String address;

    @Column(name="student_email")
    private String email;

    @Column(name="student_username")
    private String username;

    @Column(name="student_password")
    private String password;

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy="pk.student")
    private Set<StudentCourse> studentCourses;

    public Student() {
        studentCourses = new HashSet<StudentCourse>(0);
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Set<StudentCourse> getCourses() {
        return studentCourses;
    }

    public void setCourses(Set<StudentCourse> studentCourses) {
        this.studentCourses = studentCourses;
    }


}

Course

@Component
@Entity
@Table(name="Course")
public class Course {

    @Id
    @Column(name="course_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    @Column(name="course_name")
    private String name;
    @Column(name="course_schedule")
    private String schedule;    
    @ManyToOne
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;

    @JsonBackReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy="pk.course")
    private Set<StudentCourse> studentCourses = new HashSet<StudentCourse>(0);

    public Course() {

    }


    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    public Long getId() {
        return id;
    }


    public void setId(Long id) {
        this.id = id;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSchedule() {
        return schedule;
    }

    public void setSchedule(String schedule) {
        this.schedule = schedule;
    }

    public Set<StudentCourse> getStudentCourses() {
        return studentCourses;
    }

    public void setStudentCourses(Set<StudentCourse> studentCourses) {
        this.studentCourses = studentCourses;
    }


}

Studentcourse

@Component
@Entity
@Table(name="Student_Course")
@AssociationOverrides({
    @AssociationOverride(name = "pk.student", 
        joinColumns = @JoinColumn(name = "student_id")),
    @AssociationOverride(name = "pk.course", 
        joinColumns = @JoinColumn(name = "course_id")) })
public class StudentCourse implements java.io.Serializable {

    @EmbeddedId
    private StudentCourseId pk = new StudentCourseId();

    public StudentCourseId getPk() {
        return pk;
    }

    public void setPk(StudentCourseId pk) {
        this.pk = pk;
    }

    @Transient
    public Student getStudent() {
        return getPk().getStudent();
    }

    public void setStudent(Student student) {
        getPk().setStudent(student);
    }

    @Transient
    public Course getCourse() {
        return getPk().getCourse();
    }

    public void setCourse(Course course) {
        getPk().setCourse(course);
    }


}

Studentcourseid

@Embeddable
public class StudentCourseId implements java.io.Serializable {


    @ManyToOne
    private Student student;
    @ManyToOne
    private Course course;

    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        StudentCourseId that = (StudentCourseId) o;

        if (student != null ? !student.equals(that.student) : that.student != null) return false;
        if (course != null ? !course.equals(that.course) : that.course != null)
            return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = (student != null ? student.hashCode() : 0);
        result = 31 * result + (course != null ? course.hashCode() : 0);
        return result;
    }
}

Service

//find a student by its ID
public Optional<Student> getStudentById(Long studentID) throws SQLException{

    return studentRepo.findById(studentID);
}

Controller

//find a student by its ID
@GetMapping("/findStudent/{studentID}")
public ResponseEntity<?> getStudentById(@PathVariable Long studentID){      

    student = sts.getStudentById(studentID).orElse(new Student());
    return new ResponseEntity<>(student, HttpStatus.OK);
}

Json Response

enter image description here

down from "studentCourses" I would like to have the list of courses that the student has registered, but is returning me an infinite recursion of the student himself...

Thanks in advance.

1 answer

1


You are having infinite recursion because Jackson is not knowing where to stop serializing your object, without seeing all the stacktrace, I suspect it is at the time he is writing the Studentcourseid.

When he starts writing Student and arrives at the studentCourses property and tries to write the Studentcourseid type pk, note that you have a reference for Student again.

Try using the @Jsonignoreproperties annotation on top of the Studentcourseid student attribute (repeat in Ourse if necessary).

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

...

@ManyToOne
@JsonIgnoreProperties({"studentCourses"})
private Student student;

@ManyToOne
@JsonIgnoreProperties({"studentCourses"})
private Course course;
  • 1

    really, it was a problem in Jackson’s Parsing, gave to solve with @JsonIgnoreProperties and also worked by announcing the class level with @JsonIdentityInfo . Thank you very much!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.