Scenario: - I created an entity manager - I queried a list of entities - I called parallelStream on them, and called some getters which resulted in loading additional entities - I cleaned the entity manager - I repeated the process, and a NullPointerException was thrown during cleaning
Stacktrace:
{code:java} java.lang.NullPointerException at org.hibernate.engine.internal.StatefulPersistenceContext.clear(StatefulPersistenceContext.java:234) at org.hibernate.internal.SessionImpl.cleanupOnClose(SessionImpl.java:572) at org.hibernate.internal.AbstractSharedSessionContract.setClosed(AbstractSharedSessionContract.java:315) at org.hibernate.internal.AbstractSharedSessionContract.close(AbstractSharedSessionContract.java:308) at org.hibernate.internal.SessionImpl.close(SessionImpl.java:412) {code}
Test case:
{code:java}
private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("JPA_PERSISTENCE_UNIT_NAME");
@Test public void testHibernate() throws InterruptedException { run(); run(); //exception thrown only for 2nd run }
public void run() throws InterruptedException { EntityManager em = entityManagerFactory.createEntityManager(); try {
List<MyEntity> entities = em.createQuery("from MyEntity").getResultList(); entities.parallelStream() .forEach((e) -> { //only happens when loading at least 2 different referenced entities e.getReferencedEntity().getId(); e.getAnotherReferencedEntity().getId(); }); } finally { em.close(); } } {code}
Where MyEntity looks like:
{code:java} @Entity @Table(name = "my_entity") @Audited public class MyEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "id_a") @Audited(targetAuditMode=RelationTargetAuditMode.NOT_AUDITED) private A referencedEntity;
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "id_b) @Audited(targetAuditMode=RelationTargetAuditMode.NOT_AUDITED) private B anotherReferencedEntity;
//Constructor, getters, setters
} {code}
The exception is thrown at StatefulPersistenceContext.java:234, which is: {code:java} for ( Entry<Object, EntityEntry> objectEntityEntryEntry : entityEntryContext.reentrantSafeEntityEntries() ) { // todo : I dont think this need be reentrant safe if ( objectEntityEntryEntry.getKey() instanceof PersistentAttributeInterceptable ) { //<-- this line ... {code} While debugging I discovered that entityEntryContext.reentrantSafeEntityEntries() returned a collection an array in which some elements were null.
The issue doesn't appear if I replace the parallelStream() with a simple stream(). |
|