Issue
I have this object named SubmittedQuiz, it consists of a Quiz object, User object and submittedQuestions object.
When I try to do this request:
GET http://localhost:8080/SubmittedQuiz/getForUser/10
I get returned the following error:
Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->edowl.Model.SubmittedQuiz["user"]->edowl.Model.User$HibernateProxy$lNsgwyQb["hibernateLazyInitializer"])"
The request finds the objects fine, when setting breakpoints it actually gets the list of objects however it fails on the return statement.
The controller method is as shown below:
@GetMapping("/getForUser/{id}")
public ResponseEntity<List<SubmittedQuiz>> getSubmittedQuizForUser(@PathVariable("id") Long id){
List<SubmittedQuiz> quizzes = submittedQuizService.findAllByUserId(id);
return new ResponseEntity<>(quizzes, HttpStatus.OK); //ok is 200 status code
}
The Service is shown below:
public List<SubmittedQuiz> findAllByUserId(Long id) {
return submittedQuizRepo.findAllByUserId(id);
}
The Repo is shown below:
List<SubmittedQuiz> findAllByUserId(Long id);
The SubmittedQuiz
is shown below:
@Entity
@Table(name = "Submitted_Quiz")
public class SubmittedQuiz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name = "User_Quiz_Submitted",
joinColumns = { @JoinColumn(name = "quiz_submitted_id")},
inverseJoinColumns = { @JoinColumn(name = "user_id")})
public User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name = "Quiz_Quiz_Submitted",
joinColumns = { @JoinColumn(name = "quiz_submitted_id")},
inverseJoinColumns = { @JoinColumn(name = "quiz_id")})
public Quiz quiz;
private float score;
private LocalDate generatedDate;
private float timeTaken;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "quiz_submitted_question",
joinColumns = { @JoinColumn(name = "quiz_submitted_id")},
inverseJoinColumns = { @JoinColumn(name = "question_id")})
@Column(name = "submitted_questions")
private Set<SubmittedQuestion> submittedQuestions = new HashSet<>();
I saw one suggestion about putting @JsonBackReference
& @JsonManagedReference
annotations on the objects.
However I haven't needed to do this on any other object thus far and the current annotations I have used sufficed fine till this point
Are there any suggestions?
Solution
You could try to use EntityGraph for this purpose.
And set to atributePaths
all entities which have FetchType.LAZY
:
@EntityGraph(attributePaths = {"user", "quiz", "submitted_questions"})
List<SubmittedQuiz> findAllByUserId(Long id);
Some hint for controller - you don't need to set 200
response directly. Status code OK
is returned by default. So following will be fine:
@GetMapping("/getForUser/{id}")
public List<SubmittedQuiz> getSubmittedQuizForUser(@PathVariable("id") Long id){
return submittedQuizService.findAllByUserId(id);
}
UPDATE:
Try to add web configuration like::
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public Module datatypeHibernateModule() {
return new Hibernate5Module();
}
}
If it wouldn't help to solve the issue with the error try to add:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
to all your subentities:
@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(...)
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public User user;
Also, JPA API requires that your entities have to be serializable. You have to update it like follows:
public class SubmittedQuiz implements Serializable {
private static final long serialVersionUID = 1L;
Add the same for other entities as well (User, Quiz...)
Answered By - catch23
Answer Checked By - Mary Flores (JavaFixing Volunteer)