1

I don't understand behaviour of FetchType.LAZY in my situation. In one case hibernate is working as expected (it doesn't fetch entities marked as FetchType.LAZY), but when it comes to the other entity hibernate is fetching the associated entities even though they are marked as FetchType.LAZY, too.

I have two entities, which are relevant to this problem. Their snippets (with controllers and services):

Post:

@Entity
@Table(name = "POST")
@ToString @Getter @Setter @RequiredArgsConstructor
@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class Post extends BaseEntity {

    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    private Set<Comment> comments = new HashSet<>();
}

Comment:

@Entity
@Table(name = "COMMENT")
@ToString @Getter @Setter @RequiredArgsConstructor
@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class Comment extends BaseEntity {

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    @JoinColumn(name = "post_id")
    private Post post;
}

BaseEntity:

@MappedSuperclass
@Getter @Setter
public class BaseEntity {
    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
}

Their controllers & services:

PostController:

@RestController
@RequestMapping("/api/posts")

public class PostController {

private final PostService postService;

@Autowired
public PostController(PostService postService) {
    this.postService = postService;
}

@GetMapping
public List<Post> getAllPosts(Pageable pageableRequest){
   Page<Post> resultPage = postService.getAll(pageableRequest);
   if(pageableRequest.getPageNumber() > resultPage.getTotalPages()){
       throw new InvalidOperationException("Page not found. Last available page: " + resultPage.getTotalPages());
   }

   return resultPage.getContent();
}

PostService:

@Service
@Transactional
public class PostService {

    private final PostRepository postRepository;

    @Autowired
    public PostService(PostRepository postRepository) {
        this.postRepository = postRepository;
    }


    public Page<Post> getAll(Pageable pageableRequest) {
        return postRepository.findAll(pageableRequest);
    }
}

postRepository.findAll(pageableRequest) method is from PagingAndSortingRepository.

CommentController:

@RestController
@RequestMapping("/api/comments")
public class CommentController {

    private final CommentService commentService;

    @Autowired
    public CommentController(CommentService commentService) {
        this.commentService = commentService;
    }

    @GetMapping
    public List<Comment> getAllComments(){
        return commentService.getAll();
    }
}

CommentService:

@Service
@Transactional
public class CommentService {

    private final CommentRepository commentRepository;

    @Autowired
    public CommentService(CommentRepository commentRepository) {
        this.commentRepository = commentRepository;
    }

    public List<Comment> getAll(){
        return commentRepository.findAll();
    }
}

commentRepository.findAll() is from JpaRepository.

When I'm trying to get all the comments (using endpoint "/api/comments") hibernate is working fine in my opinion and the exception is thrown, because entity is not fetched form the database:

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]->pl.app.model.Comment["post"]->pl.app.model.Post$HibernateProxy$d4g0rJFB["hibernateLazyInitializer"])] with root cause

Problem is when I try to get posts (using endpoint "/api/posts") - the comments are fetched. Hibernate creates select statements to get comments of the posts:

    Hibernate: select post0_.id as id1_2_, post0_.content as content2_2_, post0_.user_id as user_id3_2_ from post post0_ limit ?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?

If I get comment (Post is an association in Comment), those select statements are created (and after last select statement exception is thrown):

Hibernate: select comment0_.id as id1_1_, comment0_.content as content2_1_, comment0_.user_id as user_id3_1_, comment0_.post_id as post_id4_1_ from comment comment0_
Hibernate: select post0_.id as id1_2_0_, post0_.content as content2_2_0_, post0_.user_id as user_id3_2_0_ from post post0_ where post0_.id=?
Hibernate: select categories0_.post_id as post_id1_0_0_, categories0_.category as category2_0_0_ from category categories0_ where categories0_.post_id=?
Hibernate: select comments0_.post_id as post_id4_1_0_, comments0_.id as id1_1_0_, comments0_.id as id1_1_1_, comments0_.content as content2_1_1_, comments0_.user_id as user_id3_1_1_, comments0_.post_id as post_id4_1_1_ from comment comments0_ where comments0_.post_id=?

My questions are:

Why hibernate is fetching comments when I explicitly stated FetchType.LAZY on comments collection in Post entity?

Maybe it's the other way around? That means Post should be fetched when I get Comment even though there is FetchType.LAZY used?

  • Does this answer your question? [Avoid Jackson serialization on non fetched lazy objects](https://stackoverflow.com/questions/21708339/avoid-jackson-serialization-on-non-fetched-lazy-objects) – Ishank Gulati Mar 29 '20 at 10:05
  • @IshankGulati Unfortunetly not, my question wasn't about how to not serialize unfetched object. It was about why collection of associated entities are even fetched even though lazy fetch type was stated. – ProgrammingProblems Mar 29 '20 at 10:19
  • FetchType lazy means that your entities will be fetched when used. Jackson tries to access your lazy entities while serializing your object, that's why they get fetched. Let me know if you need more clarification. – Ishank Gulati Mar 29 '20 at 10:41
  • @IshankGulati So why Jackson failes to access Post from a comment entity? It's the same situation - Post is lazily fetched, but exception is thrown. – ProgrammingProblems Mar 29 '20 at 10:57
  • Can you enable hibernate showSql and post the queries generated by hibernate here? – Ishank Gulati Mar 29 '20 at 11:51
  • @IshankGulati I've edited my question – ProgrammingProblems Mar 30 '20 at 15:51

0 Answers0