Springboot - list of objects with child entities not returned

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 1:

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...)