NonIdentifierAttribute.isLazy() returns false when @Basic(fetch=FetchType.LAZY)
Description
Attachments
1
causes
is fixed by
relates to
Activity
Show:

Luis Barreiro July 12, 2016 at 8:36 PM
That would be

Former user July 12, 2016 at 1:59 AM
I've added a test case to reproduce this issue and pushed to 5.0, 5.1, and master branches.
The fix for this issue in 5.1 and master branches was tracked by a different jira (not sure which one).

Luis Barreiro July 12, 2016 at 12:38 AM
is a follow up.

Former user June 22, 2016 at 10:20 PM
I'm reopening this because it causes HHH-10865.

Former user June 10, 2016 at 11:46 PM
Fixed in 5.0 branch only as the bug only affected 5.0.
When setting the
enableLazyInitialization
parameter of thehibernate-enhance-maven-plugin
's configuration totrue
, the non-identifier attributes annotated with@Basic(fetch = FetchType.LAZY)
will show asLazyPropertyInitializer.UNFETCHED_PROPERTY
inEntityEntry.getLoadedState()
, whileAbstractEntityTuplizer.getPropertyValues(Object)
will shownull
current values becauseNonIdentifierAttribute.isLazy()
returnsfalse
.This causes a problem in
DefaultFlushEntityEventListener.dirtyCheck(FlushEntityEvent)
, where the two different representations are stored in the following two variables:And then (when there is no
findDirty()
interceptor override, and the entity is not an instance ofSelfDirtinessTracker
, so theenableDirtyTracking
parameter of thehibernate-enhance-maven-plugin
configuration isfalse
), the dirty check is performed by [AbstractEntityPersister.findDirty(Object[] currentState, Object[] previousState, Object entity, SessionImplementor session)
|https://github.com/hibernate/hibernate-orm/blob/5.0.8/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java#L4079], and then forwarded to [TypeHelper.findDirty(NonIdentifierAttribute[] properties, Object[] currentState, Object[] previousState, boolean[][] includeColumns, boolean anyUninitializedProperties, SessionImplementor session)
|https://github.com/hibernate/hibernate-orm/blob/5.0.8/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java#L282]. This checks if the current state holdsLazyPropertyInitializer.UNFETCHED_PROPERTY
, but it holdsnull
instead (as described in the first paragraph). These two values are then compared in the appropriateType
subclass'isDirty()
,isSame()
andisEqual()
methods, which (depending on the actual implementation) either return an incorrect dirty state (and then an unnecessary UPDATE is scheduled inDefaultFlushEntityEventListener.onFlushEntity(FlushEntityEvent)
), or throw an exception (e.g.ClassCastException
when comparing a primitive byte array toLazyPropertyInitializer.UNFETCHED_PROPERTY
.In my opinion, the problem lies in
NonIdentifierAttribute.isLazy()
returningfalse
inAbstractEntityTuplizer.getPropertyValues(Object)
, causing the current state array to holdnull
instead ofLazyPropertyInitializer.UNFETCHED_PROPERTY
. These different values are also visible in [Interceptor.findDirty(Object, Serializable, Object[], Object[], String[], Type[])
|https://github.com/hibernate/hibernate-orm/blob/5.0.8/hibernate-core/src/main/java/org/hibernate/Interceptor.java#L198]'scurrentState
andpreviousState
arrays. (As far as I can tell, noType
subclasses are prepared to handleLazyPropertyInitializer.UNFETCHED_PROPERTY
directly, so it shouldn't be propagated to them fromTypeHelper.findDirty()
.)The code path of the error that I've observed:
DefaultFlushEntityEventListener.onFlushEntity(FlushEntityEvent)
DefaultFlushEntityEventListener.isUpdateNecessary(FlushEntityEvent, boolean)
DefaultFlushEntityEventListener.dirtyCheck(FlushEntityEvent)
[
AbstractEntityPersister.findDirty(Object[], Object[], Object, SessionImplementor)
|https://github.com/hibernate/hibernate-orm/blob/5.0.8/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java#L4079][
TypeHelper.findDirty(NonIdentifierAttribute[], Object[], Object[], boolean[][], boolean, SessionImplementor)
|https://github.com/hibernate/hibernate-orm/blob/5.0.8/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java#L282][
Type.isDirty(Object, Object, boolean[], SessionImplementor)
|https://github.com/hibernate/hibernate-orm/blob/5.0.8/hibernate-core/src/main/java/org/hibernate/type/Type.java#L263]Type.isDirty(Object, Object, SessionImplementor)
Type.isSame(Object, Object)
Type.isEqual(Object, Object)
First I've observed this problem with a
UserType
field, but I could reproduce it withbyte[]
too.Setting
enableDirtyTracking
totrue
is a possible workaround, asDefaultFlushEntityEventListener.dirtyCheck(FlushEntityEvent)
uses a different code path in that case.My original
hibernate-enhance-maven-plugin
configuration: