I've been trying to solve a problem with a NullPointerException in a Hibernate class when I set the fetch attribute of a @OneToMany field to FetchType.EAGER. I assume I'm doing something wrong but I can't see what, can anyone help?
This is the error:
Code:
Caused by: java.lang.NullPointerException
at org.hibernate.engine.internal.StatefulPersistenceContext.getLoadedCollectionOwnerOrNull(StatefulPersistenceContext.java:780)
at org.hibernate.event.spi.AbstractCollectionEvent.getLoadedOwnerOrNull(AbstractCollectionEvent.java:58)
at org.hibernate.event.spi.InitializeCollectionEvent.<init>(InitializeCollectionEvent.java:22)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2002)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:562)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:246)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:558)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:131)
at org.hibernate.collection.internal.PersistentSet.toArray(PersistentSet.java:170)
at testhib.entities.Parent.$$_hibernate_write_children(Parent.java)
... 64 more
This is the test case I've constructed:
Database
Code:
CREATE TABLE `test`.`parent` (
`parent_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_version` int(10) unsigned NOT NULL DEFAULT '1',
`parent_name` varchar(64) DEFAULT NULL,
PRIMARY KEY (`parent_id`)
);
CREATE TABLE `test`.`child` (
`child_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`child_version` int(10) unsigned NOT NULL DEFAULT '1',
`child_name` varchar(64) DEFAULT NULL,
`child_parent` int(10) unsigned NOT NULL,
PRIMARY KEY (`child_id`),
KEY `fk_child_1_idx` (`child_parent`),
CONSTRAINT `fk_child_1` FOREIGN KEY (`child_parent`) REFERENCES `parent` (`parent_id`)
);
INSERT INTO `test`.`parent`
(`parent_id`, `parent_name`)
VALUES
(1, 'Homer');
INSERT INTO `test`.`child`
(`child_id`, `child_name`, `child_parent`)
VALUES
(1, 'Bart', 1),
(2, 'Lisa', 1),
(3, 'Maggie', 1);
Entities
Code:
package testhib.entities;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import static javax.persistence.FetchType.EAGER;
@Entity
@Table(name = "parent")
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "parent_id")
private Integer parentId;
@Basic(optional = false)
@Column(name = "parent_version")
private int parentVersion;
@Column(name = "parent_name")
private String parentName;
@OneToMany(mappedBy = "parent", fetch = EAGER)
private Set<Child> children;
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public int getParentVersion() {
return parentVersion;
}
public void setParentVersion(int parentVersion) {
this.parentVersion = parentVersion;
}
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
public Set<Child> getChildren() {
return children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}
}
package testhib.entities;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "child")
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "child_id")
private Integer childId;
@Basic(optional = false)
@Column(name = "child_version")
private int childVersion;
@Column(name = "child_name")
private String childName;
@JoinColumn(name = "child_parent", referencedColumnName = "parent_id")
@ManyToOne
private Parent parent;
public Integer getChildId() {
return childId;
}
public void setChildId(Integer childId) {
this.childId = childId;
}
public int getChildVersion() {
return childVersion;
}
public void setChildVersion(int childVersion) {
this.childVersion = childVersion;
}
public String getChildName() {
return childName;
}
public void setChildName(String childName) {
this.childName = childName;
}
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
Test
Code:
package testhib.test;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import testhib.entities.Parent;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
public class Tests {
private static EntityManagerFactory emf;
private EntityManager em;
public Tests() {
}
@BeforeClass
public static void setUpClass() {
emf = Persistence.createEntityManagerFactory("test-hib");
}
@AfterClass
public static void tearDownClass() {
emf.close();
}
@Before
public void setUp() {
em = emf.createEntityManager();
em.getTransaction().begin();
}
@After
public void tearDown() {
em.getTransaction().commit();
em.close();
}
@Test
public void canRead() {
Parent p = em.find(Parent.class, 1);
Set<String> names = new HashSet<>();
p.getChildren().stream().forEach((c) -> {
names.add(c.getChildName());
});
assertThat(names, containsInAnyOrder("Bart", "Lisa", "Maggie"));
}
}
peristence.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="test-hib" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>testhib.entities.Parent</class>
<class>testhib.entities.Child</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
<property name="javax.persistence.jdbc.user" value="test"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="password"/>
</properties>
</persistence-unit>
</persistence>
POM
Code:
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>uk.co.discoverdorset</groupId>
<artifactId>test-hib</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test-hib</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.1.0.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>5.1.0.Final</version>
<executions>
<execution>
<configuration>
<failOnError>true</failOnError>
<enableLazyInitialization>true</enableLazyInitialization>
<enableDirtyTracking>true</enableDirtyTracking>
<enableAssociationManagement>true</enableAssociationManagement>
<enableExtendedEnhancement>false</enableExtendedEnhancement>
</configuration>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The test runs without a hitch if I comment out the "fetch = EAGER" from the Parent entity.
Any ideas?