Many to Many API Java Spring Boot

Viewed 162

I'm just learning Spring Boot and doing a small project I got stuck with. I have a many to many relationship between Students and Courses, there is a table in the middle called enrollment for this relationship which takes the student_id and course_id as the primary key. I am creating an API for the above-mentioned. I have next

  1. Class Student
  2. Class Enrollment
  3. Class Course
  4. Class StudentRepository
  5. Class StudentJPAResource

Class Student

package com.myapis.rest.webservices.restfulwebservicesedgar01.student;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import com.myapis.rest.webservices.restfulwebservicesedgar01.enrollment.Enrollment;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;


@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "STUD_SEQ")
    @SequenceGenerator(sequenceName = "student_id_seq", allocationSize = 1, name = "STUD_SEQ")
    private Integer studentId;
    
    @Size(min=2, message="Name should have at least two chars")
    private String firstName;
    private String lastName;
    
    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL)
    @JsonIgnore
    private List<Enrollment> enrollments = new ArrayList<>();
    
    @Past
    private Date birthDate;
    
    public Student() {}

    public Student(Integer studentId, String firstName, String lastName, Date birthDate) {
        super();
        this.studentId = studentId;
        this.firstName = firstName;
        this.birthDate = birthDate;
    }
    
    public Integer getId() {
        return studentId;
    }
    
    public void setId(Integer id) {
        this.studentId = studentId;
    }
    public String getFirstName() {
        return firstName;
    }
    
    public String getLastName() {
        return lastName;
    }
    
    public void setfirstName(String firstName) {
        this.firstName = firstName;
    }
    public Date getBirthDate() {
        return birthDate;
    }
    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public List<Enrollment> getEnrollments() {
        return enrollments;
    }

    @Override
    public String toString() {
        
        return "Student [studentId=" + studentId + ", firstName=" + firstName + ", lastName=" + lastName + ", payments="
                + payments + ", birthDate=" + birthDate + "]";
    
    }
}

Class Enrollment

package com.myapis.rest.webservices.restfulwebservicesedgar01.enrollment;

import java.util.Date;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;

import com.myapis.rest.webservices.restfulwebservicesedgar01.course.Course;
import com.myapis.rest.webservices.restfulwebservicesedgar01.student.Student;
import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity(name="Enrollment")
@Table(name="enrollments")
public class Enrollment {

    @EmbeddedId
    private EnrollmentId id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("studentId")
    @JoinColumn(name="student_id")
    @JsonIgnore
    private Student student;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("courseId")
    @JoinColumn(name="course_id")
    @JsonIgnore
    private Course course;
    
    @Column(name="enrollment_id")
    private Integer enrollmentId;
    
    @Column(name="date_enrollment")
    private Date enrollmentDate;
    
    public Enrollment() {}
    
    public Enrollment(Student student, Course course, Integer enrollmentId, Date enrollmentDate) {
        super();
        this.id = new EnrollmentId(student.getId(), course.getId());
        this.student = student;
        this.course = course;
        this.enrollmentId = enrollmentId;
        this.enrollmentDate = enrollmentDate;
    }
    
    public EnrollmentId getId() {
        return id;
    }

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

    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 Integer getEnrollmentId() {
        return enrollmentId;
    }

    public void setEnrollmentId(Integer enrollmentId) {
        this.enrollmentId = enrollmentId;
    }

    public Date getEnrollmentDate() {
        return enrollmentDate;
    }

    public void setEnrollmentDate(Date enrollmentDate) {
        this.enrollmentDate = enrollmentDate;
    }

    @Override
    public String toString() {
        return "Enrollment [id=" + id + ", student=" + student + ", course=" + course + ", enrollmentId=" + enrollmentId
                + ", enrollmentDate=" + enrollmentDate + "]";
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
 
        if (o == null || getClass() != o.getClass())
            return false;
 
        Enrollment that = (Enrollment) o;
        return Objects.equals(student, that.student) &&
               Objects.equals(course, that.course);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(student, course);
    }
}

Class Course

package com.myapis.rest.webservices.restfulwebservicesedgar01.course;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;

import com.myapis.rest.webservices.restfulwebservicesedgar01.enrollment.Enrollment;
import com.myapis.rest.webservices.restfulwebservicesedgar01.student.Student;

@Entity
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "COURSE_SEQ")
    @SequenceGenerator(sequenceName = "course_id_seq", allocationSize = 1, name = "COURSE_SEQ")
    private Integer courseId;
    
    private String courseName;
    private String description;
    
    @OneToMany(mappedBy = "course", cascade = CascadeType.ALL)
    private List<Enrollment> enrollments = new ArrayList<>();
    
    
    public Course() {}  
    
    public Course(Integer courseId, String courseName, String description) {
        super();
        this.courseId = courseId;
        this.courseName = courseName;
        this.description = description;
    }
    
    public Integer getId() {
        return courseId;
    }
    
    public Integer getCourseId() {
        return courseId;
    }
    public void setCourseId(Integer courseId) {
        this.courseId = courseId;
    }
    public String getCourseName() {
        return courseName;
    }
    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Course [courseId=" + courseId + ", courseName=" + courseName + ", description=" + description + "]";
    }
    
    
}

Class Enrollment

package com.myapis.rest.webservices.restfulwebservicesedgar01.enrollment;

import java.util.Date;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;

import com.myapis.rest.webservices.restfulwebservicesedgar01.course.Course;
import com.myapis.rest.webservices.restfulwebservicesedgar01.student.Student;
import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity(name="Enrollment")
@Table(name="enrollments")
public class Enrollment {

    @EmbeddedId
    private EnrollmentId id;
    
    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("studentId")
    @JoinColumn(name="student_id")
    @JsonIgnore
    private Student student;
    
    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("courseId")
    @JoinColumn(name="course_id")
    @JsonIgnore
    private Course course;
    
    @Column(name="enrollment_id")
    private Integer enrollmentId;
    
    @Column(name="date_enrollment")
    private Date enrollmentDate;
    
    public Enrollment() {}
    
    public Enrollment(Student student, Course course, Integer enrollmentId, Date enrollmentDate) {
        super();
        this.id = new EnrollmentId(student.getId(), course.getId());
        this.student = student;
        this.course = course;
        this.enrollmentId = enrollmentId;
        this.enrollmentDate = enrollmentDate;
    }
    
    public EnrollmentId getId() {
        return id;
    }

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

    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 Integer getEnrollmentId() {
        return enrollmentId;
    }

    public void setEnrollmentId(Integer enrollmentId) {
        this.enrollmentId = enrollmentId;
    }

    public Date getEnrollmentDate() {
        return enrollmentDate;
    }

    public void setEnrollmentDate(Date enrollmentDate) {
        this.enrollmentDate = enrollmentDate;
    }

    @Override
    public String toString() {
        return "Enrollment [id=" + id + ", student=" + student + ", course=" + course + ", enrollmentId=" + enrollmentId
                + ", enrollmentDate=" + enrollmentDate + "]";
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
 
        if (o == null || getClass() != o.getClass())
            return false;
 
        Enrollment that = (Enrollment) o;
        return Objects.equals(student, that.student) &&
               Objects.equals(course, that.course);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(student, course);
    }
}

Class StudentRepository

package com.edgarapis.rest.webservices.restfulwebservicesedgar01.student;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Integer>{
    
}

Class StudentJPAResource

package com.myapis.rest.webservices.restfulwebservicesedgar01.student;

import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import com.myapis.rest.webservices.restfulwebservicesedgar01.payment.Payment;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.MapperFeature;
import com.myapis.rest.webservices.restfulwebservicesedgar01.enrollment.Enrollment;

@RestController 
public class StudentJPAResource {
    
    @Autowired
    private StudentRepository studentRepository;
    
    //retrieve all students
    @GetMapping("/jpa/students")
    public List<Student> retrieveAllStudents() {
        return studentRepository.findAll();
    }

    //retrieve one user by id from studentRepository
    @GetMapping("/jpa/students/{id}")
    public EntityModel<Optional<Student>> retriveStudent(@PathVariable int id) {
        Optional<Student> student = studentRepository.findById(id);
        
        if(!student.isPresent()) {
            throw new StudentNotFoundException("id - " + id);
        }
        
        //"all-students", SERVER_PATH + "/students"
        //RetrieveAllStudents
        EntityModel<Optional<Student>> resource = EntityModel.of(student);
        
        //From the library WebMvcLinkBuilder
        WebMvcLinkBuilder linkTo = WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(this.getClass()).retrieveAllStudents());
        
        resource.add(linkTo.withRel("all-students"));
        
        return resource;
    }   
    
    //deleting one user by id
    @DeleteMapping("/jpa/students/{id}")
    public void deleteStudent(@PathVariable int id) {
        studentRepository.deleteById(id);
    }
    
    //Save one user to the persistence layer
    @PostMapping("/jpa/students")
    public ResponseEntity<Object> createStudent(@Valid @RequestBody Student student) {
        Student savedStudent = studentRepository.save(student);
        
        // /user/{id} -- Response back indicating the user creation was good
        URI location = ServletUriComponentsBuilder
            .fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(savedStudent.getId()).toUri();
        
        return ResponseEntity.created(location).build();  
    }
    

    //All courses that one specific student is enrolled
    @GetMapping("/jpa/students/{id}/enrollments")
    public List<Enrollment> retrieveOneStudentCourses(@PathVariable int id) {
        Optional<Student> studentOptional = studentRepository.findById(id);
        
        if(!studentOptional.isPresent()) {
            throw new StudentNotFoundException("id - " + id);
        }
        
        return studentOptional.get().getEnrollments();
    }
    
    //All Students with their courses
    @GetMapping("/jpa/students/enrollments")
    public List<Student> retrieveAllStudentsCourses() {
    // How to implement???  
    }   
}

In the class StudentJPAResource, method retrieveOneStudentCourses, I created this method to retrieve the courses of a specific student. I want to create a method to retrieve all the students and the courses that they are enrolled retrieveAllStudentsCourses().

NOTE Currently, in the class student, I have the notation @JsonIgnore for Enrollment because when I use retrieveAllStudents() the students come up with their enrollments so, this notation prevents this, otherwise, the students will come up with the enrollments (that is actually what I want to do, but using a different method).

Thank you for your help, beforehand.

0 Answers
Related