Issue
My Project class -
@Entity
public class Project {
@Id
private Integer projectId;
private String projectName;
@ManyToMany(mappedBy = "projects")
private List<Employee> employees;
}
@Entity
public class Employee {
@Id
private Integer employeeId;
private String employeeName;
@ManyToMany
private List<Project> projects;
}
My main class -
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Employee employee1 = new Employee();
employee1.setEmployeeId(1);
employee1.setEmployeeName("Harry");
Employee employee2 = new Employee();
employee2.setEmployeeId(2);
employee2.setEmployeeName("Ron");
Project project1 = new Project();
project1.setProjectId(3);
project1.setProjectName("ABC");
Project project2 = new Project();
project2.setProjectId(4);
project2.setProjectName("DEF");
List<Project> projectList = new ArrayList<>();
projectList.add(project1);
projectList.add(project2);
employee1.setProjects(projectList);
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(employee1);
session.save(employee2);
session.save(project1);
session.save(project2);
transaction.commit();
Project project3 = session.get(Project.class, 3);
System.out.println(project3.getProjectId() + " " + project3.getProjectName());
for(Employee employee : project3.getEmployees()){
System.out.println(employee.getEmployeeId()+" "+ employee.getEmployeeName());
}
session.close();
sessionFactory.close();
On running the above code, employee1, employee2, project1, project2 are successfully saved into the database but I get a NullPointerException
with project3.getEmployees()
.
But the next time I run the code (with all the save commands commented), project3.getEmployees()
is not null and contains Employee(employeeId=1, employeeName="Harry").
Is there any time lag because of which the first time I get a NullPointerException
with project3.getEmployees()
?
Note - project3.getProjectId()
and project3.getProjectName()
don't return null in either of the cases.
Solution
You have to manually manage the relationship properly between Project
and Employee
before they are saved to DB. To facilitate it , you can create an instance method on Employee
to encapsulate such logic rather than directly set the employee 's project list.
public class Employee {
public void addProject(Project project){
this.projects.add(project);
project.getEmployees().add(this);
}
}
And manage their relationships by :
employee1.addProject(project1);
employee1.addProject(project2);
Of course you can do it in other way round , which add an employee to a project :
public class Project {
public void addEmployee(Employee employee){
this.employees.add(employee);
employee.getProjects().add(this);
}
}
And manage their relationship by :
project1.addEmployee(employee1);
project2.addEmployee(employee1);
When you get project3
, it just return you the project1
instance from the Session
as both project1
and project3
refer to the same ID. Since you do not manage project1
's employees properly before , it has NULL employees list and hence you get NullPointerException
.
The time when you execute it again , project3
is loaded from the DB which hibernate already help to manage their relationship automatically and hence you do not get NullPointerException
If you do want to manage the relationship by yourself, you can call session.refresh(employee1)
after the transaction is commit to force hibernate to refresh its latest state from the DB which should not solve the NullPointerException
:
....
transaction.commit();
session.refresh(project1);
Project project3 = session.get(Project.class, 3);
System.out.println(project3.getProjectId() + " " + project3.getProjectName());
for(Employee employee : project3.getEmployees()){
System.out.println(employee.getEmployeeId()+" "+ employee.getEmployeeName());
}
Answered By - Ken Chan
Answer Checked By - Marie Seifert (JavaFixing Admin)