Skip to content

Commit 3650daa

Browse files
committed
HHH-19605 Fix entity dirtiness logic when dealing with proxies
1 parent 15dc518 commit 3650daa

File tree

2 files changed

+34
-29
lines changed

2 files changed

+34
-29
lines changed

hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryImpl.java

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,8 @@
3737
import static org.hibernate.engine.internal.EntityEntryImpl.EnumState.PREVIOUS_STATUS;
3838
import static org.hibernate.engine.internal.EntityEntryImpl.EnumState.STATUS;
3939
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
40-
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
40+
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptableOrNull;
4141
import static org.hibernate.engine.internal.ManagedTypeHelper.asSelfDirtinessTracker;
42-
import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy;
43-
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
4442
import static org.hibernate.engine.internal.ManagedTypeHelper.isSelfDirtinessTracker;
4543
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfManagedEntity;
4644
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker;
@@ -385,9 +383,17 @@ private boolean isUnequivocallyNonDirty(Object entity) {
385383
}
386384

387385
private boolean isNonDirtyViaCustomStrategy(Object entity) {
388-
if ( isPersistentAttributeInterceptable( entity ) ) {
389-
if ( asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor()
390-
instanceof EnhancementAsProxyLazinessInterceptor ) {
386+
final var interceptable = asPersistentAttributeInterceptableOrNull( entity );
387+
if ( interceptable != null ) {
388+
if ( interceptable.$$_hibernate_getInterceptor() instanceof EnhancementAsProxyLazinessInterceptor interceptor
389+
&& !interceptor.isInitialized() ) {
390+
// we never have to check an uninitialized proxy
391+
return true;
392+
}
393+
}
394+
else {
395+
final var lazyInitializer = extractLazyInitializer( entity );
396+
if ( lazyInitializer != null && lazyInitializer.isUninitialized() ) {
391397
// we never have to check an uninitialized proxy
392398
return true;
393399
}
@@ -400,28 +406,24 @@ private boolean isNonDirtyViaCustomStrategy(Object entity) {
400406
}
401407

402408
private boolean isNonDirtyViaTracker(Object entity) {
403-
final boolean uninitializedProxy;
404-
if ( isPersistentAttributeInterceptable( entity ) ) {
405-
if ( asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor()
406-
instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) {
407-
return !lazinessInterceptor.hasWrittenFieldNames();
409+
final var interceptable = asPersistentAttributeInterceptableOrNull( entity );
410+
if ( interceptable != null ) {
411+
if ( interceptable.$$_hibernate_getInterceptor() instanceof EnhancementAsProxyLazinessInterceptor interceptor ) {
412+
return !interceptor.hasWrittenFieldNames();
408413
}
409-
else {
410-
uninitializedProxy = false;
411-
}
412-
}
413-
else if ( isHibernateProxy( entity ) ) {
414-
uninitializedProxy = extractLazyInitializer( entity ).isUninitialized();
415414
}
416415
else {
417-
uninitializedProxy = false;
416+
final var lazyInitializer = extractLazyInitializer( entity );
417+
if ( lazyInitializer != null && lazyInitializer.isUninitialized() ) {
418+
// we never have to check an uninitialized proxy
419+
return true;
420+
}
418421
}
419422
// we never have to check an uninitialized proxy
420-
return uninitializedProxy
421-
|| !persister.hasCollections()
422-
&& !persister.hasMutableProperties()
423-
&& !asSelfDirtinessTracker( entity ).$$_hibernate_hasDirtyAttributes()
424-
&& asManagedEntity( entity ).$$_hibernate_useTracker();
423+
return !persister.hasCollections()
424+
&& !persister.hasMutableProperties()
425+
&& asManagedEntity( entity ).$$_hibernate_useTracker()
426+
&& !asSelfDirtinessTracker( entity ).$$_hibernate_hasDirtyAttributes();
425427
}
426428

427429
@Override

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDirtyCheckEventListener.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import org.hibernate.persister.collection.CollectionPersister;
1717
import org.hibernate.persister.entity.EntityPersister;
1818

19+
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
20+
1921

2022
/**
2123
* Determines if the current session holds modified state which
@@ -61,22 +63,23 @@ public void onDirtyCheck(DirtyCheckEvent event) throws HibernateException {
6163

6264
private static boolean isEntityDirty(EntityHolder holder, EventSource session) {
6365
final var entityEntry = holder.getEntityEntry();
64-
final Status status = entityEntry.getStatus();
66+
final Status status = castNonNull( entityEntry ).getStatus();
6567
return switch ( status ) {
6668
case GONE, READ_ONLY -> false;
6769
case DELETED -> true;
68-
case MANAGED -> isManagedEntityDirty( holder.getManagedObject(), holder.getDescriptor(), entityEntry, session );
70+
case MANAGED -> isManagedEntityDirty( holder, entityEntry, session );
6971
case SAVING, LOADING -> throw new AssertionFailure( "Unexpected status: " + status );
7072
};
7173
}
7274

73-
private static boolean isManagedEntityDirty(
74-
Object entity, EntityPersister descriptor, EntityEntry entityEntry, EventSource session) {
75-
if ( entityEntry.requiresDirtyCheck( entity ) ) { // takes into account CustomEntityDirtinessStrategy
75+
private static boolean isManagedEntityDirty(EntityHolder holder, EntityEntry entityEntry, EventSource session) {
76+
if ( entityEntry.requiresDirtyCheck( holder.getManagedObject() ) ) { // takes into account CustomEntityDirtinessStrategy
77+
final Object entity = holder.getEntity();
78+
final EntityPersister descriptor = holder.getDescriptor();
7679
final Object[] propertyValues =
7780
entityEntry.getStatus() == Status.DELETED
7881
? entityEntry.getDeletedState()
79-
: descriptor.getValues( entity );
82+
: descriptor.getValues( holder.getEntity() );
8083
final int[] dirty =
8184
descriptor.findDirty( propertyValues, entityEntry.getLoadedState(), entity, session );
8285
return dirty != null;

0 commit comments

Comments
 (0)