ManagedEntity linked list broken when mutable, non-associated enhanced entity is evicted

Description

I have encountered NullPointerException exceptions coming from Hibernate's internals:

I was doing something like the following in a (stateful) Session:

Lazy attribute loading is enabled with the following hibernate-enhance-maven-plugin parameters, but the involved @OneToMany relation doesn't have to be FetchType.LAZY.

Removing the evict() call resolves the issue.

Both places where the exception occured was calling StatefulPersistenceContext.reentrantSafeEntityEntries() internally, which returns an array by calling EntityEntryContext.reentrantSafeEntityEntries(). After evicting an entity, this array contained only null values (instead of EntityEntryContext.EntityEntryCrossRefImpl instances), and calling Map.Entry.getValue() or Map.Entry.getKey() on these null values resulted in the NullPointerException errors.

By looking at the source code of EntityEntryContext.reentrantSafeEntityEntries(), I can see that it creates a new array of size count, and fills the items of this new array by walking the ManagedEntity linked list from head by calling $$_hibernate_getNextManagedEntity(). However, count is non-zero and head is null here, so we get an array of count null values.

And by debugging DefaultEvictEventListener.onEvict(), I could see that it reaches line 89 without throwing an (ignored) exception there. (The doEvict() method is not called in this code path.) Only the StatefulPersistenceContext.removeEntry() method is called, which in turn calls EntityEntryContext.removeEntityEntry().

Debugging this EntityEntryContext.removeEntityEntry() method shows that the argument is an instance of ManagedEntity in line 174 (because of the bytecode enhancement), but in lines 189 and 190, its $$_hibernate_getPreviousManagedEntity() and $$_hibernate_getNextManagedEntity() methods return null (its bytecode enhanced $$_hibernate_previousManagedEntity and $$_hibernate_nextManagedEntity fields were also null upon inspection). So in lines 210 and 219, the head and tail variables are set to null (the assert operations would also fail). So in the subsequent call of reentrantSafeEntityEntries() runs with a null head and non-zero count, causing the NullPointerException errors.

I couldn't figure out why this child entity had null values for the $$_hibernate_previousManagedEntity, $$_hibernate_nextManagedEntity and $$_hibernate_entityEntryHolder fields, but this might be the cause of the exceptions. Other managed entities of the session (including the parent entity) had non-null values.

Setting the enableLazyInitialization parameter of the hibernate-enhance-maven-plugin to false also resolves the problem.

Environment

None

Assignee

Gail Badner

Reporter

Gábor Varga

Fix versions

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

Priority

Blocker
Configure