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
- Class Student
- Class Enrollment
- Class Course
- Class StudentRepository
- 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.