diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java index e4089b499b..cddc79f1cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java @@ -37,6 +37,8 @@ import net.bytebuddy.implementation.bytecode.member.MethodInvocation; import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess; import net.bytebuddy.jar.asm.Opcodes; +import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeTracker; + class CodeTemplates { static class SetOwner { @@ -319,14 +321,14 @@ class CodeTemplates { @Advice.OnMethodEnter static void enter(@FieldName String fieldName, @FieldValue Object field) { if ( field != null ) { - ( (CompositeTracker) field ).$$_hibernate_clearOwner( fieldName ); + asCompositeTracker( field ).$$_hibernate_clearOwner( fieldName ); } } @Advice.OnMethodExit static void exit(@Advice.This CompositeOwner self, @FieldName String fieldName, @FieldValue Object field) { if ( field != null ) { - ( (CompositeTracker) field ).$$_hibernate_setOwner( fieldName, self ); + asCompositeTracker( field ).$$_hibernate_setOwner( fieldName, self ); } self.$$_hibernate_trackChange( fieldName ); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java index 416ce04adb..0925251223 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java @@ -22,6 +22,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.CompositeType; import org.hibernate.type.Type; +import static org.hibernate.engine.internal.ManagedTypeHelper.asSelfDirtinessTracker; import static org.hibernate.engine.internal.ManagedTypeHelper.isSelfDirtinessTrackerType; /** @@ -280,7 +281,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter } if ( inLineDirtyChecking ) { - ( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( attributeName ); + asSelfDirtinessTracker( target ).$$_hibernate_trackChange( attributeName ); } } else { @@ -293,7 +294,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter } writtenFieldNames.add( attributeName ); - ( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( attributeName ); + asSelfDirtinessTracker( target ).$$_hibernate_trackChange( attributeName ); } return newValue; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java index de4bb6bab1..f6fc6b7f19 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java @@ -6,6 +6,8 @@ */ package org.hibernate.engine.internal; +import org.hibernate.engine.spi.CompositeOwner; +import org.hibernate.engine.spi.CompositeTracker; import org.hibernate.engine.spi.PrimeAmongSecondarySupertypes; import org.hibernate.engine.spi.Managed; import org.hibernate.engine.spi.ManagedEntity; @@ -128,6 +130,29 @@ public final class ManagedTypeHelper { return false; } + /** + * @param entity + * @return true if and only if the entity implements {@see CompositeOwner} + */ + public static boolean isCompositeOwner(final Object entity) { + if ( entity instanceof PrimeAmongSecondarySupertypes ) { + PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity; + return t.asCompositeOwner() != null; + } + return false; + } + + /** + * @param entity + * @return true if and only if the entity implements {@see CompositeTracker} + */ + public static boolean isCompositeTracker(final Object entity) { + if ( entity instanceof PrimeAmongSecondarySupertypes ) { + PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity; + return t.asCompositeTracker() != null; + } + return false; + } /** * Helper to execute an action on an entity, but exclusively if it's implementing the {@see PersistentAttributeInterceptable} @@ -248,6 +273,43 @@ public final class ManagedTypeHelper { throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to ManagedEntity" ); } + /** + * Cast the object to CompositeTracker + * (using this is highly preferrable over a direct cast) + * @param entity the entity to cast + * @return the same instance after casting + * @throws ClassCastException if it's not of the right type + */ + public static CompositeTracker asCompositeTracker(final Object entity) { + Objects.requireNonNull( entity ); + if ( entity instanceof PrimeAmongSecondarySupertypes ) { + PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity; + final CompositeTracker e = t.asCompositeTracker(); + if ( e != null ) { + return e; + } + } + throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to CompositeTracker" ); + } + /** + * Cast the object to CompositeOwner + * (using this is highly preferrable over a direct cast) + * @param entity the entity to cast + * @return the same instance after casting + * @throws ClassCastException if it's not of the right type + */ + public static CompositeOwner asCompositeOwner(final Object entity) { + Objects.requireNonNull( entity ); + if ( entity instanceof PrimeAmongSecondarySupertypes ) { + PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity; + final CompositeOwner e = t.asCompositeOwner(); + if ( e != null ) { + return e; + } + } + throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to CompositeOwner" ); + } + /** * Cast the object to SelfDirtinessTracker * (using this is highly preferrable over a direct cast) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeOwner.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeOwner.java index a16870380e..c7715a893c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeOwner.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeOwner.java @@ -9,9 +9,15 @@ package org.hibernate.engine.spi; /** * @author Ståle W. Pedersen */ -public interface CompositeOwner { +public interface CompositeOwner extends PrimeAmongSecondarySupertypes { /** * @param attributeName to be added to the dirty list */ void $$_hibernate_trackChange(String attributeName); + + @Override + default CompositeOwner asCompositeOwner() { + return this; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeTracker.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeTracker.java index a863774bfb..f15ee45cdd 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeTracker.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/CompositeTracker.java @@ -9,9 +9,15 @@ package org.hibernate.engine.spi; /** * @author Ståle W. Pedersen */ -public interface CompositeTracker { +public interface CompositeTracker extends PrimeAmongSecondarySupertypes { void $$_hibernate_setOwner(String name, CompositeOwner tracker); void $$_hibernate_clearOwner(String name); + + @Override + default CompositeTracker asCompositeTracker() { + return this; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java index 25e78bbc33..625513c368 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java @@ -45,4 +45,12 @@ public interface PrimeAmongSecondarySupertypes { return null; } + default CompositeOwner asCompositeOwner() { + return null; + } + + default CompositeTracker asCompositeTracker() { + return null; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 70974a24ab..3153a3d828 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -273,6 +273,7 @@ import org.hibernate.type.Type; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.MutabilityPlan; +import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.processIfPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker; @@ -1370,7 +1371,7 @@ public abstract class AbstractEntityPersister public Object initializeLazyProperty(String fieldName, Object entity, SharedSessionContractImplementor session) { final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityEntry entry = persistenceContext.getEntry( entity ); - final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); + final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor(); assert interceptor != null : "Expecting bytecode interceptor to be non-null"; if ( hasCollections() ) { @@ -1494,7 +1495,7 @@ public abstract class AbstractEntityPersister throw new AssertionFailure( "no lazy properties" ); } - final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); + final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor(); assert interceptor != null : "Expecting bytecode interceptor to be non-null"; LOG.tracef( "Initializing lazy properties from datastore (triggered for `%s`)", fieldName ); diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java index f68417a2c6..2a706fd695 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java @@ -10,12 +10,16 @@ import java.io.Serializable; import java.lang.reflect.Field; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.engine.internal.ManagedTypeHelper; import org.hibernate.engine.spi.CompositeOwner; import org.hibernate.engine.spi.CompositeTracker; import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.property.access.internal.AbstractFieldSerialForm; +import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeOwner; +import static org.hibernate.engine.internal.ManagedTypeHelper.asCompositeTracker; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; +import static org.hibernate.engine.internal.ManagedTypeHelper.isCompositeTracker; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptableType; /** @@ -49,8 +53,8 @@ public class EnhancedSetterImpl extends SetterFieldImpl { super.set( target, value ); // This sets the component relation for dirty tracking purposes - if ( ( enhancementState & COMPOSITE_OWNER ) != 0 && ( ( enhancementState & COMPOSITE_TRACKER_MASK ) != 0 && value != null || value instanceof CompositeTracker ) ) { - ( (CompositeTracker) value ).$$_hibernate_setOwner( propertyName, (CompositeOwner) target ); + if ( ( enhancementState & COMPOSITE_OWNER ) != 0 && ( ( enhancementState & COMPOSITE_TRACKER_MASK ) != 0 && value != null || isCompositeTracker( value ) ) ) { + asCompositeTracker( value ).$$_hibernate_setOwner( propertyName, asCompositeOwner( target ) ); } // This marks the attribute as initialized, so it doesn't get lazily loaded afterwards