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?