I started working on my project and wanted to use Hibernate along with JpaRepositories. Since I'm not familiar with these that might be a dumb question, however, I can not find out why are my associated collections initialized eagerly.
My classes (simplified):
@Entity(name = "board")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Board_Type")
public abstract class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "board_id", updatable = false)
private Long boardId;
@Column(name = "board_name")
private String boardName;
@ManyToMany
@JoinTable(name = "board_status",
joinColumns = {@JoinColumn(name = "fk_board")},
inverseJoinColumns = {@JoinColumn(name = "fk_status")})
private Set<Status> availableStatuses = new HashSet<>();
@OneToMany(mappedBy = "board", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
private List<Task> taskList = new ArrayList<>();
Sub-class:
@Entity
@DiscriminatorValue(value = "Simple_Board")
public class SimpleBoard extends Board{
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
private User owner;
Task class:
@Entity(name = "task")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "task_id)
private Long taskId;
private String taskName;
@OneToMany(mappedBy = "task", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
private List<Comment> commentList = new ArrayList<>();;
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
private User creator;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
@JsonBackReference
private Board board;
Comment class:
@Entity(name = "comment")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "comment_id", updatable = false)
private Long commentId;
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
private User creator;
private String content;
private LocalDateTime creationDate;
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
private Task task;
User class:
@Entity(name = "user")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "User_Type")
public abstract class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id", updatable = false)
private Long userId;
private String login;
private String password;
private String email;
private LocalDateTime registerDate;
User sub-class:
@Entity
@DiscriminatorValue(value = "App_User")
public class ApplicationUser extends User{
private String firstName;
private String lastName;
@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JsonManagedReference
private List<SimpleBoard> personalBoards = new ArrayList<>();
@OneToMany(mappedBy="creator", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JsonManagedReference
private List<Task> userTasks = new ArrayList<>();
Endpoint called to get Board with given Id:
@RestController
@RequestMapping("/board")
public class SimpleBoardController {
private ApplicationUserService applicationUserService;
private SimpleBoardService simpleBoardService;
@Autowired
public SimpleBoardController(SimpleBoardService simpleBoardService, ApplicationUserService applicationUserService) {
this.simpleBoardService = simpleBoardService;
this.applicationUserService = applicationUserService;
}
@GetMapping(value = "/{boardId}")
public SimpleBoard getBoard(@PathVariable Long id){
return simpleBoardService.getBoardById(id);
}
Service method:
@Override
public SimpleBoard getBoardById(Long id) {
return simpleBoardDAO.getByBoardId(id);
}
JpaRepository:
public interface SimpleBoardDAO extends JpaRepository<SimpleBoard, Long> {
SimpleBoard save(SimpleBoard simpleBoard);
SimpleBoard getByBoardId(Long id);
I use H2-db, in order to create some test data I use data.sql. Then I use postman to call the endpoint and the response is like that:
{
"boardId": 1,
"boardName": "Test Board",
"availableStatuses": [
{
"statusId": 3,
"name": "Done",
"sequence": 2
},
{
"statusId": 2,
"name": "In Progress",
"sequence": 2
},
{
"statusId": 1,
"name": "To Do",
"sequence": 1
}
],
"taskList": [
{
"taskId": 1,
"taskName": "Create an To Do Application",
"commentList": [
{
"commentId": 1,
"content": "Nice job",
"creationDate": "2021-09-23T20:36:39.026"
}
],
"creationDate": "2021-09-23T20:36:39.024",
"status": {
"statusId": 1,
"name": "To Do",
"sequence": 1
}
}
]
}
I expect this endpoint to either return Board without associated Tasks and Comments or throw an Exception since I didn't use any graphs or JPQL Join Fetch methods to initialize these collections. As you can see the Board was fetched together with both of them. I know that this might happen in debugger mode or by calling some methods related to the collections, but I don't do anything like that.
The purpose of this project is to learn JPA and Hibernate. I know that the data model might be a mess and I need to overthink that once again. Hopefully, somebody can explain that to me. Thanks in advance!
P.S. I am aware of the fact that lazy fetching is a default one and putting FetchType on both sides of the association is redundant. I was just desperate :D