Reputation: 13
Course.java
package com.example.jpa_training.JPAD.model;
@Entity
@Table(name = "COURSE")
public class Course implements Serializable{
public Course() {}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
private String description;
@ManyToOne(targetEntity=Department.class)
@JsonIgnore
private Department department;
@ManyToMany(mappedBy="courses", targetEntity=Student.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JsonIgnore
private Set<Student> students = new HashSet<Student>();
@ManyToOne(cascade = CascadeType.MERGE)
@JoinColumn(name="professor_id")
@JsonManagedReference
private Professor professor;
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 Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Professor getProfessor() {
return professor;
}
public void setProfessor(Professor professor) {
this.professor = professor;
}
public Set<Student> getStudents() {
return students;
}
public void addStudent(Student student) {
this.students.add(student);
}
public void removeStudent(Student student) {
this.students.remove(student);
}
@OneToMany(mappedBy = "course", fetch = FetchType.LAZY)
private Set<Review> reviews;
}
Review.java
@Entity
public class Review implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long reviewId;
@ManyToOne
private Course course;
private String reviewDescription;
private double courseRating;
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public String getReviewDescription() {
return reviewDescription;
}
public void setReviewDescription(String reviewDescription) {
this.reviewDescription = reviewDescription;
}
public double getCourseRating() {
return courseRating;
}
public void setCourseRating(double courseRating) {
this.courseRating = courseRating;
}
}
Postman Input
{
"course": {
"id": 4,
"name": "Data Analysis",
"description": "Just take it",
"professor": {
"name": "Kapil Dev",
"qualification": "M.Tech",
"department": {
"deptId": 1,
"deptName": "Big Data",
"buildingName": "DS-04"
}
}
},
"reviewDescription": "Good course, nice teaching",
"courseRating": 0.0
}
Error Log
Failed to evaluate Jackson deserialization for type [[simple type, class com.example.jpa_training.JPAD.model.Review]]: com.fasterxml.jackson.databind.JsonMappingException: 2020-12-30 11:45:00.869 WARN 11152 --- [nio-8080-exec-2] .c.j.MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class com.example.jpa_training.JPAD.model.Review]]: com.fasterxml.jackson.databind.JsonMappingException: 2020-12-30 11:45:00.869 WARN 11152 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported]
Tried solutions
Using @JsonBackReference and @JsonManagedReference Using @JsonIdentityInfo and @JsonIgnore but the error is the same I can save and retrieve the data from Java but when I send data over postman or using curl command I get the above error, I tried many ways but couldn't fix it
Upvotes: 1
Views: 1935
Reputation: 673
I wouldn't suggest exposing entities directly to your controller. Entities should only contain JPA annotations in your case. You can expose a DTO (Data Transfer Object) to your controller and then map the DTO to the corresponding entity.
ReviewDto
public class ReviewDto {
private String reviewDescription;
private double courseRating;
private CourseDto course;
// getters, setters, etc
}
CourseDto
public class CourseDto {
private Long id;
private String name;
private String description;
// professorDto, getters, setters, etc
}
An example demonstrating how your controller class will be
@RestController
public class DemoController {
private final ReviewDtoMapper reviewDtoMapper;
private final ReviewService reviewService;
public DemoController(ReviewDtoMapper reviewDtoMapper,
ReviewService reviewService) {
this.reviewDtoMapper = reviewDtoMapper;
this.reviewService = reviewService;
}
@PostMapping(value = "demo")
public ResponseEntity<String> postReview(@RequestBody ReviewDto reviewDto) {
final Review review = reviewDtoMapper.mapFrom(reviewDto);
reviewService.save(review);
return ResponseEntity.ok("");
}
}
The class to map from reviewDto to review entity and the opposite.
@Component
public class ReviewDtoMapper {
public ReviewDto mapTo(final Review entity) {
ReviewDto reviewDto = new ReviewDto();
reviewDto.setReviewDescription(entity.getReviewDescription());
// set all the properties you want
return reviewDto;
}
public Review mapFrom(ReviewDto dto) {
Review review = new Review();
review.setReviewDescription(dto.getReviewDescription());
// set all the properties you want
return review;
}
}
Of course, you have to make adjustments according to your needs.
If you like this way of doing things I would suggest you check MapStruct, it will automatically make the mappers for you.
Upvotes: 1