HHH-15616 Mitigate performance impact of entity enhancement on Klass's _secondary_super_cache
This commit is contained in:
parent
16c39c0925
commit
53076f3029
|
@ -28,6 +28,7 @@ import org.hibernate.collection.spi.PersistentSet;
|
|||
import org.hibernate.collection.spi.PersistentSortedMap;
|
||||
import org.hibernate.collection.spi.PersistentSortedSet;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -108,8 +109,10 @@ public final class Hibernate {
|
|||
if ( proxy instanceof HibernateProxy ) {
|
||||
return !( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUninitialized();
|
||||
}
|
||||
else if ( proxy instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) proxy ).$$_hibernate_getInterceptor();
|
||||
else if ( ManagedTypeHelper.isPersistentAttributeInterceptable( proxy ) ) {
|
||||
final PersistentAttributeInterceptable asPersistentAttributeInterceptable = ManagedTypeHelper.asPersistentAttributeInterceptable(
|
||||
proxy );
|
||||
final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable.$$_hibernate_getInterceptor();
|
||||
return !(interceptor instanceof EnhancementAsProxyLazinessInterceptor);
|
||||
}
|
||||
else if ( proxy instanceof LazyInitializable ) {
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterc
|
|||
import org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState;
|
||||
import org.hibernate.engine.spi.CompositeOwner;
|
||||
import org.hibernate.engine.spi.CompositeTracker;
|
||||
import org.hibernate.engine.spi.EnhancedEntity;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.ExtendedSelfDirtinessTracker;
|
||||
import org.hibernate.engine.spi.Managed;
|
||||
|
@ -176,6 +177,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
log.debugf( "Skipping enhancement of [%s]: already enhanced", managedCtClass.getName() );
|
||||
return null;
|
||||
}
|
||||
final EnhancementStatus es = new EnhancementStatus( managedCtClass.getName() );
|
||||
|
||||
builder = builder.annotateType( HIBERNATE_VERSION_ANNOTATION );
|
||||
|
||||
|
@ -184,6 +186,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
builder = builder.implement( ManagedEntity.class )
|
||||
.defineMethod( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME, Object.class, Visibility.PUBLIC )
|
||||
.intercept( FixedValue.self() );
|
||||
es.enabledInterfaceManagedEntity();
|
||||
|
||||
builder = addFieldWithGetterAndSetter(
|
||||
builder,
|
||||
|
@ -207,7 +210,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
EnhancerConstants.NEXT_SETTER_NAME
|
||||
);
|
||||
|
||||
builder = addInterceptorHandling( builder, managedCtClass );
|
||||
builder = addInterceptorHandling( builder, managedCtClass, es );
|
||||
|
||||
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
|
||||
List<AnnotatedFieldDescription> collectionFields = collectCollectionFields( managedCtClass );
|
||||
|
@ -230,8 +233,10 @@ public class EnhancerImpl implements Enhancer {
|
|||
.intercept( implementationSuspendDirtyTracking )
|
||||
.defineMethod( EnhancerConstants.TRACKER_COLLECTION_GET_NAME, CollectionTracker.class, Visibility.PUBLIC )
|
||||
.intercept( implementationGetCollectionTrackerWithoutCollections );
|
||||
es.enabledInterfaceSelfDirtinessTracker();
|
||||
}
|
||||
else {
|
||||
//TODO es.enableInterfaceExtendedSelfDirtinessTracker ? Careful with consequences..
|
||||
builder = builder.implement( ExtendedSelfDirtinessTracker.class )
|
||||
.defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldPersistence.TRANSIENT, Visibility.PRIVATE )
|
||||
.annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() )
|
||||
|
@ -326,13 +331,13 @@ public class EnhancerImpl implements Enhancer {
|
|||
}
|
||||
}
|
||||
|
||||
return createTransformer( managedCtClass ).applyTo( builder );
|
||||
return createTransformer( managedCtClass ).applyTo( builder, es );
|
||||
}
|
||||
else if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
|
||||
log.debugf( "Enhancing [%s] as Composite", managedCtClass.getName() );
|
||||
|
||||
builder = builder.implement( ManagedComposite.class );
|
||||
builder = addInterceptorHandling( builder, managedCtClass );
|
||||
builder = addInterceptorHandling( builder, managedCtClass, es );
|
||||
|
||||
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
|
||||
builder = builder.implement( CompositeTracker.class )
|
||||
|
@ -359,17 +364,17 @@ public class EnhancerImpl implements Enhancer {
|
|||
.intercept( implementationClearOwner );
|
||||
}
|
||||
|
||||
return createTransformer( managedCtClass ).applyTo( builder );
|
||||
return createTransformer( managedCtClass ).applyTo( builder, es );
|
||||
}
|
||||
else if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
|
||||
log.debugf( "Enhancing [%s] as MappedSuperclass", managedCtClass.getName() );
|
||||
|
||||
builder = builder.implement( ManagedMappedSuperclass.class );
|
||||
return createTransformer( managedCtClass ).applyTo( builder );
|
||||
return createTransformer( managedCtClass ).applyTo( builder, es );
|
||||
}
|
||||
else if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
|
||||
log.debugf( "Extended enhancement of [%s]", managedCtClass.getName() );
|
||||
return createTransformer( managedCtClass ).applyExtended( builder );
|
||||
return createTransformer( managedCtClass ).applyExtended( builder, es );
|
||||
}
|
||||
else {
|
||||
log.debugf( "Skipping enhancement of [%s]: not entity or composite", managedCtClass.getName() );
|
||||
|
@ -391,12 +396,13 @@ public class EnhancerImpl implements Enhancer {
|
|||
return false;
|
||||
}
|
||||
|
||||
private DynamicType.Builder<?> addInterceptorHandling(DynamicType.Builder<?> builder, TypeDescription managedCtClass) {
|
||||
private DynamicType.Builder<?> addInterceptorHandling(DynamicType.Builder<?> builder, TypeDescription managedCtClass, EnhancementStatus es) {
|
||||
// interceptor handling is only needed if class has lazy-loadable attributes
|
||||
if ( enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) {
|
||||
log.debugf( "Weaving in PersistentAttributeInterceptable implementation on [%s]", managedCtClass.getName() );
|
||||
|
||||
builder = builder.implement( PersistentAttributeInterceptable.class );
|
||||
es.enabledInterfacePersistentAttributeInterceptable();
|
||||
|
||||
builder = addFieldWithGetterAndSetter(
|
||||
builder,
|
||||
|
@ -616,4 +622,53 @@ public class EnhancerImpl implements Enhancer {
|
|||
this.resolution = new Resolution.Explicit( bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to keep track of which interfaces are being applied,
|
||||
* so to attempt dodging the performance implications of for https://bugs.openjdk.org/browse/JDK-8180450
|
||||
* We're optimising for the case in which entities are fully enhanced.
|
||||
*/
|
||||
final static class EnhancementStatus {
|
||||
|
||||
private final String typeName;
|
||||
private boolean managedEntity = false;
|
||||
private boolean selfDirtynessTracker = false;
|
||||
private boolean persistentAttributeInterceptable = false;
|
||||
private boolean applied = false;
|
||||
|
||||
public EnhancementStatus(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
public void enabledInterfaceManagedEntity() {
|
||||
this.managedEntity = true;
|
||||
}
|
||||
|
||||
public void enabledInterfaceSelfDirtinessTracker() {
|
||||
this.selfDirtynessTracker = true;
|
||||
}
|
||||
|
||||
public void enabledInterfacePersistentAttributeInterceptable() {
|
||||
this.persistentAttributeInterceptable = true;
|
||||
}
|
||||
|
||||
public DynamicType.Builder<?> applySuperInterfaceOptimisations(DynamicType.Builder<?> builder) {
|
||||
if ( applied ) {
|
||||
throw new IllegalStateException("Should not apply super-interface optimisations twice");
|
||||
}
|
||||
else {
|
||||
applied = true;
|
||||
if ( managedEntity && persistentAttributeInterceptable && selfDirtynessTracker ) {
|
||||
log.debugf( "Applying Enhancer optimisations for type [%s]; adding EnhancedEntity as additional marker.", typeName );
|
||||
return builder.implement( EnhancedEntity.class );
|
||||
}
|
||||
else {
|
||||
log.debugf( "Applying Enhancer optimisations for type [%s]; NOT enabling EnhancedEntity as additional marker.", typeName );
|
||||
}
|
||||
//TODO consider applying a marker for other combinations of interfaces as well?
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -207,7 +207,8 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
|
|||
return null;
|
||||
}
|
||||
|
||||
DynamicType.Builder<?> applyTo(DynamicType.Builder<?> builder) {
|
||||
DynamicType.Builder<?> applyTo(DynamicType.Builder<?> builder, EnhancerImpl.EnhancementStatus es) {
|
||||
builder = es.applySuperInterfaceOptimisations(builder);
|
||||
boolean compositeOwner = false;
|
||||
|
||||
builder = builder.visit( new AsmVisitorWrapper.ForDeclaredMethods().invokable( NOT_HIBERNATE_GENERATED, this ) );
|
||||
|
@ -262,7 +263,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
|
|||
}
|
||||
|
||||
if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
|
||||
builder = applyExtended( builder );
|
||||
builder = applyExtended( builder, es );
|
||||
}
|
||||
|
||||
return builder;
|
||||
|
@ -311,7 +312,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
|
|||
}
|
||||
}
|
||||
|
||||
DynamicType.Builder<?> applyExtended(DynamicType.Builder<?> builder) {
|
||||
DynamicType.Builder<?> applyExtended(DynamicType.Builder<?> builder, EnhancerImpl.EnhancementStatus es) {
|
||||
AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper enhancer = new FieldAccessEnhancer( managedCtClass, enhancementContext, classPool );
|
||||
return builder.visit( new AsmVisitorWrapper.ForDeclaredMethods().invokable( NOT_HIBERNATE_GENERATED, enhancer ) );
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.bytecode.BytecodeLogging;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -72,7 +73,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter
|
|||
}
|
||||
}
|
||||
|
||||
this.inLineDirtyChecking = SelfDirtinessTracker.class.isAssignableFrom( entityPersister.getMappedClass() );
|
||||
this.inLineDirtyChecking = ManagedTypeHelper.isSelfDirtinessTrackerType( entityPersister.getMappedClass() );
|
||||
// if self-dirty tracking is enabled but DynamicUpdate is not enabled then we need to initialise the entity
|
||||
// because the pre-computed update statement contains even not dirty properties and so we need all the values
|
||||
// we have to initialise it even if it's versioned to fetch the current version
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.engine.spi.CachedNaturalIdValueSource;
|
|||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityEntryExtraState;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.Managed;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
|
@ -259,9 +260,7 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
getPersister().setValue( entity, getPersister().getVersionProperty(), nextVersion );
|
||||
}
|
||||
|
||||
if( entity instanceof SelfDirtinessTracker ) {
|
||||
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
ManagedTypeHelper.processIfSelfDirtinessTracker( entity, AbstractEntityEntry::clearDirtyAttributes );
|
||||
|
||||
getPersistenceContext().getSession()
|
||||
.getFactory()
|
||||
|
@ -269,6 +268,10 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
.resetDirty( entity, getPersister(), (Session) getPersistenceContext().getSession() );
|
||||
}
|
||||
|
||||
private static void clearDirtyAttributes(final SelfDirtinessTracker entity) {
|
||||
entity.$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDelete() {
|
||||
setCompressedValue( EnumState.PREVIOUS_STATUS, getStatus() );
|
||||
|
@ -325,10 +328,10 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
|
||||
@SuppressWarnings( {"SimplifiableIfStatement"})
|
||||
private boolean isUnequivocallyNonDirty(Object entity) {
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
if ( ManagedTypeHelper.isSelfDirtinessTracker( entity ) ) {
|
||||
boolean uninitializedProxy = false;
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) entity;
|
||||
if ( ManagedTypeHelper.isPersistentAttributeInterceptable( entity ) ) {
|
||||
final PersistentAttributeInterceptable interceptable = ManagedTypeHelper.asPersistentAttributeInterceptable( entity );
|
||||
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
|
||||
EnhancementAsProxyLazinessInterceptor enhancementAsProxyLazinessInterceptor = (EnhancementAsProxyLazinessInterceptor) interceptor;
|
||||
|
@ -342,11 +345,11 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
// we never have to check an uninitialized proxy
|
||||
return uninitializedProxy || !persister.hasCollections()
|
||||
&& !persister.hasMutableProperties()
|
||||
&& !( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
|
||||
&& !ManagedTypeHelper.asSelfDirtinessTracker( entity ).$$_hibernate_hasDirtyAttributes();
|
||||
}
|
||||
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) entity;
|
||||
if ( ManagedTypeHelper.isPersistentAttributeInterceptable( entity ) ) {
|
||||
final PersistentAttributeInterceptable interceptable = ManagedTypeHelper.asPersistentAttributeInterceptable( entity );
|
||||
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
|
||||
// we never have to check an uninitialized proxy
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.engine.internal;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
|
@ -90,21 +91,22 @@ public class EntityEntryContext {
|
|||
ManagedEntity managedEntity = getAssociatedManagedEntity( entity );
|
||||
final boolean alreadyAssociated = managedEntity != null;
|
||||
if ( !alreadyAssociated ) {
|
||||
if (entity instanceof ManagedEntity) {
|
||||
if ( ManagedTypeHelper.isManaged( entity ) ) {
|
||||
final ManagedEntity managed = ManagedTypeHelper.asManagedEntity( entity );
|
||||
if ( entityEntry.getPersister().isMutable() ) {
|
||||
managedEntity = (ManagedEntity) entity;
|
||||
managedEntity = managed;
|
||||
// We know that managedEntity is not associated with the same PersistenceContext.
|
||||
// Check if managedEntity is associated with a different PersistenceContext.
|
||||
checkNotAssociatedWithOtherPersistenceContextIfMutable( managedEntity );
|
||||
}
|
||||
else {
|
||||
// Create a holder for PersistenceContext-related data.
|
||||
managedEntity = new ImmutableManagedEntityHolder( (ManagedEntity) entity );
|
||||
managedEntity = new ImmutableManagedEntityHolder( managed );
|
||||
if ( immutableManagedEntityXref == null ) {
|
||||
immutableManagedEntityXref = new IdentityHashMap<>();
|
||||
}
|
||||
immutableManagedEntityXref.put(
|
||||
(ManagedEntity) entity,
|
||||
managed,
|
||||
(ImmutableManagedEntityHolder) managedEntity
|
||||
);
|
||||
}
|
||||
|
@ -149,8 +151,8 @@ public class EntityEntryContext {
|
|||
}
|
||||
|
||||
private ManagedEntity getAssociatedManagedEntity(Object entity) {
|
||||
if (entity instanceof ManagedEntity) {
|
||||
final ManagedEntity managedEntity = (ManagedEntity) entity;
|
||||
if ( ManagedTypeHelper.isManaged( entity ) ) {
|
||||
final ManagedEntity managedEntity = ManagedTypeHelper.asManagedEntity( entity );
|
||||
if ( managedEntity.$$_hibernate_getEntityEntry() == null ) {
|
||||
// it is not associated
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.engine.internal;
|
||||
|
||||
import org.hibernate.engine.spi.EnhancedEntity;
|
||||
import org.hibernate.engine.spi.Managed;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This is a helper to encapsulate an optimal strategy to execute type checks
|
||||
* for interfaces which attempts to avoid the performance issues tracked
|
||||
* as https://bugs.openjdk.org/browse/JDK-8180450 ;
|
||||
* the problem is complex and best understood by reading the OpenJDK tracker;
|
||||
* we'll focus on a possible solution here.
|
||||
* </p>
|
||||
* To avoid polluting the secondary super-type cache, the important aspect is to
|
||||
* not switch types repeatedly for the same concrete object; using a Java
|
||||
* agent which was developed for this purpose (https://github.com/franz1981/type-pollution-agent)
|
||||
* we identified a strong case with Hibernate ORM is triggered when the entities are
|
||||
* using bytecode enhancement, as they are being checked by a set of interfaces:
|
||||
* {@see org.hibernate.engine.spi.PersistentAttributeInterceptable}
|
||||
* {@see org.hibernate.engine.spi.ManagedEntity}
|
||||
* {@see org.hibernate.engine.spi.SelfDirtinessTracker}
|
||||
* {@see org.hibernate.engine.spi.Managed}
|
||||
* With our domain knowledge, we bet on the assumption that either enhancement isn't being
|
||||
* used at all, OR that when enhancement is being used, there is a strong likelyhood for
|
||||
* all of these supertypes to be have been injected into the managed objected of the domain
|
||||
* model (this isn't a certainty as otherwise we'd not have multiple interfaces to separate
|
||||
* these), but we're working based on the assumption so to at least optimise for what
|
||||
* we expect being a very common configuration.
|
||||
* (At this time we won't optimise also embeddables and other corner cases, which will
|
||||
* need to be looked at separately).
|
||||
* We therefore introduce a new marker interface {@see EnhancedEntity}, which extends
|
||||
* all these other contracts, and have the enhancer tool apply it when all other interfaces
|
||||
* have been applied.
|
||||
* This then allows to check always and consistently for this type only; as fallback
|
||||
* path, we perform the "traditional" operation as it would have been before this patch.
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
public final class ManagedTypeHelper {
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @return true if and only if the type is assignable to a {@see Managed} type.
|
||||
*/
|
||||
public static boolean isManagedType(final Class type) {
|
||||
return EnhancedEntity.class.isAssignableFrom( type ) || Managed.class.isAssignableFrom( type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @return true if and only if the entity implements {@see Managed}
|
||||
*/
|
||||
public static boolean isManaged(final Object entity) {
|
||||
return entity instanceof EnhancedEntity || entity instanceof Managed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @return true if and only if the type is assignable to a {@see PersistentAttributeInterceptable} type.
|
||||
*/
|
||||
public static boolean isPersistentAttributeInterceptableType(final Class type) {
|
||||
return EnhancedEntity.class.isAssignableFrom( type ) || PersistentAttributeInterceptable.class.isAssignableFrom( type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @return true if and only if the entity implements {@see PersistentAttributeInterceptable}
|
||||
*/
|
||||
public static boolean isPersistentAttributeInterceptable(final Object entity) {
|
||||
return entity instanceof EnhancedEntity || entity instanceof PersistentAttributeInterceptable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @return true if and only if the entity implements {@see SelfDirtinessTracker}
|
||||
*/
|
||||
public static boolean isSelfDirtinessTracker(final Object entity) {
|
||||
return entity instanceof EnhancedEntity || entity instanceof SelfDirtinessTracker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @return true if and only if the type is assignable to a {@see SelfDirtinessTracker} type.
|
||||
*/
|
||||
public static boolean isSelfDirtinessTrackerType(final Class type) {
|
||||
return EnhancedEntity.class.isAssignableFrom( type ) || SelfDirtinessTracker.class.isAssignableFrom( type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to execute an action on an entity, but exclusively if it's implementing the {@see PersistentAttributeInterceptable}
|
||||
* interface. Otherwise no action is performed.
|
||||
*
|
||||
* @param entity
|
||||
* @param action The action to be performed; it should take the entity as first parameter, and an additional parameter T as second parameter.
|
||||
* @param optionalParam a parameter which can be passed to the action
|
||||
* @param <T> the type of the additional parameter.
|
||||
*/
|
||||
public static <T> void processIfPersistentAttributeInterceptable(
|
||||
final Object entity,
|
||||
final BiConsumer<PersistentAttributeInterceptable, T> action,
|
||||
final T optionalParam) {
|
||||
if ( entity instanceof EnhancedEntity ) {
|
||||
EnhancedEntity e = (EnhancedEntity) entity;
|
||||
action.accept( e, optionalParam );
|
||||
}
|
||||
else if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
PersistentAttributeInterceptable e = (PersistentAttributeInterceptable) entity;
|
||||
action.accept( e, optionalParam );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the entity is implementing SelfDirtinessTracker, apply some action to it.
|
||||
* It is first cast to SelfDirtinessTracker using an optimal strategy.
|
||||
* If the entity does not implement SelfDirtinessTracker, no operation is performed.
|
||||
* @param entity
|
||||
* @param action
|
||||
*/
|
||||
public static void processIfSelfDirtinessTracker(final Object entity, final Consumer<SelfDirtinessTracker> action) {
|
||||
if ( entity instanceof EnhancedEntity ) {
|
||||
EnhancedEntity e = (EnhancedEntity) entity;
|
||||
action.accept( e );
|
||||
}
|
||||
else if ( entity instanceof SelfDirtinessTracker ) {
|
||||
SelfDirtinessTracker e = (SelfDirtinessTracker) entity;
|
||||
action.accept( e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast the object to PersistentAttributeInterceptable
|
||||
* (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 PersistentAttributeInterceptable asPersistentAttributeInterceptable(final Object entity) {
|
||||
if ( entity instanceof EnhancedEntity ) {
|
||||
return (EnhancedEntity) entity;
|
||||
}
|
||||
else {
|
||||
return (PersistentAttributeInterceptable) entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast the object to ManagedEntity
|
||||
* (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 ManagedEntity asManagedEntity(final Object entity) {
|
||||
if ( entity instanceof EnhancedEntity ) {
|
||||
return (EnhancedEntity) entity;
|
||||
}
|
||||
else {
|
||||
return (ManagedEntity) entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast the object to SelfDirtinessTracker
|
||||
* (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 SelfDirtinessTracker asSelfDirtinessTracker(final Object entity) {
|
||||
if ( entity instanceof EnhancedEntity ) {
|
||||
return (EnhancedEntity) entity;
|
||||
}
|
||||
else {
|
||||
return (SelfDirtinessTracker) entity;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInter
|
|||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.AssociationKey;
|
||||
import org.hibernate.engine.spi.BatchFetchQueue;
|
||||
import org.hibernate.engine.spi.CollectionEntry;
|
||||
|
@ -229,13 +230,9 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
} );
|
||||
}
|
||||
|
||||
for ( Entry<Object, EntityEntry> objectEntityEntryEntry : entityEntryContext.reentrantSafeEntityEntries() ) {
|
||||
if ( objectEntityEntryEntry.getKey() instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) objectEntityEntryEntry.getKey() ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||
( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession();
|
||||
}
|
||||
}
|
||||
for ( Entry<Object, EntityEntry> objectEntityEntryEntry : entityEntryContext.reentrantSafeEntityEntries() ) {//TODO make this a forEach process within the container
|
||||
//type-cache-pollution agent: always check for EnhancedEntity type first.
|
||||
ManagedTypeHelper.processIfPersistentAttributeInterceptable( objectEntityEntryEntry.getKey(), StatefulPersistenceContext::unsetSession, null );
|
||||
}
|
||||
|
||||
final SharedSessionContractImplementor session = getSession();
|
||||
|
@ -267,6 +264,13 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
naturalIdResolutions = null;
|
||||
}
|
||||
|
||||
private static void unsetSession(PersistentAttributeInterceptable persistentAttributeInterceptable, Object ignoredParam) {
|
||||
final PersistentAttributeInterceptor interceptor = persistentAttributeInterceptable.$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||
( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultReadOnly() {
|
||||
return defaultReadOnly;
|
||||
|
@ -670,8 +674,8 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
//initialize + unwrap the object and return it
|
||||
return li.getImplementation();
|
||||
}
|
||||
else if ( maybeProxy instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) maybeProxy;
|
||||
else if ( ManagedTypeHelper.isPersistentAttributeInterceptable( maybeProxy ) ) {
|
||||
final PersistentAttributeInterceptable interceptable = ManagedTypeHelper.asPersistentAttributeInterceptable( maybeProxy );
|
||||
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
|
||||
( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( maybeProxy, null );
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.engine.spi;
|
||||
|
||||
/**
|
||||
* This is a special marker interface designed to represent the union of several traits:
|
||||
* - ManagedEntity
|
||||
* - Managed
|
||||
* - PersistentAttributeInterceptable
|
||||
* - SelfDirtinessTracker
|
||||
* The need for such a "union" isn't natural in the Java language, but represents a technicality
|
||||
* we need to bypass performance issues caused by https://bugs.openjdk.org/browse/JDK-8180450
|
||||
* @see org.hibernate.engine.internal.ManagedTypeHelper
|
||||
* @see org.hibernate.engine.spi.Managed
|
||||
* @see org.hibernate.engine.spi.ManagedEntity
|
||||
* @see PersistentAttributeInterceptable
|
||||
* @see SelfDirtinessTracker
|
||||
*/
|
||||
public interface EnhancedEntity extends ManagedEntity, PersistentAttributeInterceptable, SelfDirtinessTracker {
|
||||
|
||||
//TODO what about ExtendedSelfDirtinessTracker ?
|
||||
//TODO CompositeTracker, ManagedMappedSuperclass
|
||||
|
||||
}
|
|
@ -15,9 +15,12 @@ import org.hibernate.StaleObjectStateException;
|
|||
import org.hibernate.action.internal.DelayedPostInsertIdentifier;
|
||||
import org.hibernate.action.internal.EntityUpdateAction;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.internal.Nullability;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.Managed;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
|
@ -99,9 +102,10 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
|
|||
}
|
||||
|
||||
private static boolean isUninitializedEnhanced(Object entity) {
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptor interceptor =
|
||||
( (PersistentAttributeInterceptable) entity).$$_hibernate_getInterceptor();
|
||||
if ( ManagedTypeHelper.isPersistentAttributeInterceptable( entity ) ) {
|
||||
final PersistentAttributeInterceptable asPersistentAttributeInterceptable = ManagedTypeHelper.asPersistentAttributeInterceptable(
|
||||
entity );
|
||||
final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable.$$_hibernate_getInterceptor();
|
||||
// the entity is an un-initialized enhancement-as-proxy reference
|
||||
return interceptor instanceof EnhancementAsProxyLazinessInterceptor;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ package org.hibernate.metamodel.internal;
|
|||
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.metamodel.spi.EntityInstantiator;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
@ -35,7 +35,8 @@ public abstract class AbstractEntityInstantiatorPojo extends AbstractPojoInstant
|
|||
this.entityMetamodel = entityMetamodel;
|
||||
this.proxyInterface = persistentClass.getProxyInterface();
|
||||
|
||||
this.applyBytecodeInterception = PersistentAttributeInterceptable.class.isAssignableFrom( persistentClass.getMappedClass() );
|
||||
//TODO this PojoEntityInstantiator appears to not be reused ?!
|
||||
this.applyBytecodeInterception = ManagedTypeHelper.isPersistentAttributeInterceptableType( persistentClass.getMappedClass() );
|
||||
}
|
||||
|
||||
protected Object applyInterception(Object entity) {
|
||||
|
@ -51,7 +52,7 @@ public abstract class AbstractEntityInstantiatorPojo extends AbstractPojoInstant
|
|||
.getLazyAttributeNames(),
|
||||
null
|
||||
);
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
ManagedTypeHelper.asPersistentAttributeInterceptable( entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.lang.reflect.Constructor;
|
|||
import org.hibernate.InstantiationException;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -47,7 +48,7 @@ public class EntityInstantiatorPojoStandard extends AbstractEntityInstantiatorPo
|
|||
? null
|
||||
: resolveConstructor( getMappedPojoClass() );
|
||||
|
||||
this.applyBytecodeInterception = PersistentAttributeInterceptable.class.isAssignableFrom( persistentClass.getMappedClass() );
|
||||
this.applyBytecodeInterception = ManagedTypeHelper.isPersistentAttributeInterceptableType( persistentClass.getMappedClass() );
|
||||
}
|
||||
|
||||
protected static Constructor<?> resolveConstructor(Class<?> mappedPojoClass) {
|
||||
|
@ -80,7 +81,7 @@ public class EntityInstantiatorPojoStandard extends AbstractEntityInstantiatorPo
|
|||
.getLazyAttributeNames(),
|
||||
null
|
||||
);
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
ManagedTypeHelper.asPersistentAttributeInterceptable( entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
|||
import org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.classic.Lifecycle;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
|
@ -99,8 +100,7 @@ public class EntityRepresentationStrategyPojoStandard implements EntityRepresent
|
|||
}
|
||||
|
||||
this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedJavaType );
|
||||
this.isBytecodeEnhanced = PersistentAttributeInterceptable.class.isAssignableFrom( mappedJavaType );
|
||||
|
||||
this.isBytecodeEnhanced = ManagedTypeHelper.isPersistentAttributeInterceptableType( mappedJavaType );
|
||||
|
||||
final Property identifierProperty = bootDescriptor.getIdentifierProperty();
|
||||
if ( identifierProperty == null ) {
|
||||
|
|
|
@ -71,6 +71,7 @@ import org.hibernate.engine.FetchTiming;
|
|||
import org.hibernate.engine.OptimisticLockStyle;
|
||||
import org.hibernate.engine.internal.CacheHelper;
|
||||
import org.hibernate.engine.internal.ImmutableEntityEntryFactory;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.internal.MutableEntityEntryFactory;
|
||||
import org.hibernate.engine.internal.StatefulPersistenceContext;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
|
@ -85,6 +86,7 @@ import org.hibernate.engine.spi.EntityEntryFactory;
|
|||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.Managed;
|
||||
import org.hibernate.engine.spi.NaturalIdResolutions;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
|
@ -4993,7 +4995,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
@Override
|
||||
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
|
||||
if ( entity instanceof PersistentAttributeInterceptable && getRepresentationStrategy().getMode() == RepresentationMode.POJO ) {
|
||||
if ( ManagedTypeHelper.isPersistentAttributeInterceptable( entity ) && getRepresentationStrategy().getMode() == RepresentationMode.POJO ) {
|
||||
final BytecodeLazyAttributeInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata()
|
||||
.extractLazyInterceptor( entity );
|
||||
assert interceptor != null;
|
||||
|
@ -5003,9 +5005,11 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
// clear the fields that are marked as dirty in the dirtiness tracker
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
ManagedTypeHelper.processIfSelfDirtinessTracker( entity, AbstractEntityPersister::clearDirtyAttributes );
|
||||
}
|
||||
|
||||
private static void clearDirtyAttributes(final SelfDirtinessTracker entity) {
|
||||
entity.$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5247,11 +5251,14 @@ public abstract class AbstractEntityPersister
|
|||
if ( session == null ) {
|
||||
return;
|
||||
}
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
final BytecodeLazyAttributeInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata().extractLazyInterceptor( entity );
|
||||
if ( interceptor != null ) {
|
||||
interceptor.setSession( session );
|
||||
}
|
||||
ManagedTypeHelper.processIfPersistentAttributeInterceptable( entity, this::setSession, session );
|
||||
}
|
||||
|
||||
private void setSession(PersistentAttributeInterceptable entity, SharedSessionContractImplementor session) {
|
||||
final BytecodeLazyAttributeInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata()
|
||||
.extractLazyInterceptor( entity );
|
||||
if ( interceptor != null ) {
|
||||
interceptor.setSession( session );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.property.access.internal;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.engine.spi.Managed;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.metamodel.RepresentationMode;
|
||||
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
|
||||
|
@ -37,7 +37,8 @@ public class PropertyAccessStrategyResolverStandardImpl implements PropertyAcces
|
|||
if ( BuiltInPropertyAccessStrategies.BASIC.getExternalName().equals( explicitAccessStrategyName )
|
||||
|| BuiltInPropertyAccessStrategies.FIELD.getExternalName().equals( explicitAccessStrategyName )
|
||||
|| BuiltInPropertyAccessStrategies.MIXED.getExternalName().equals( explicitAccessStrategyName ) ) {
|
||||
if ( Managed.class.isAssignableFrom( containerClass ) ) {
|
||||
//type-cache-pollution agent: always check for EnhancedEntity type first.
|
||||
if ( ManagedTypeHelper.isManagedType( containerClass ) ) {
|
||||
// PROPERTY (BASIC) and MIXED are not valid for bytecode enhanced entities...
|
||||
return PropertyAccessStrategyEnhancedImpl.INSTANCE;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ 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.PersistentAttributeInterceptable;
|
||||
|
@ -39,7 +40,7 @@ public class EnhancedSetterImpl extends SetterFieldImpl {
|
|||
this.propertyName = propertyName;
|
||||
this.enhancementState = ( CompositeOwner.class.isAssignableFrom( containerClass ) ? COMPOSITE_OWNER : 0 )
|
||||
| ( CompositeTracker.class.isAssignableFrom( field.getType() ) ? COMPOSITE_TRACKER_MASK : 0 )
|
||||
| ( PersistentAttributeInterceptable.class.isAssignableFrom( containerClass ) ? PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK : 0 );
|
||||
| ( ManagedTypeHelper.isPersistentAttributeInterceptableType( containerClass ) ? PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK : 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,7 +54,9 @@ public class EnhancedSetterImpl extends SetterFieldImpl {
|
|||
|
||||
// This marks the attribute as initialized, so it doesn't get lazily loaded afterwards
|
||||
if ( ( enhancementState & PERSISTENT_ATTRIBUTE_INTERCEPTABLE_MASK ) != 0 ) {
|
||||
PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor();
|
||||
final PersistentAttributeInterceptable asPersistentAttributeInterceptable = ManagedTypeHelper.asPersistentAttributeInterceptable(
|
||||
target );
|
||||
PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable.$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof BytecodeLazyAttributeInterceptor ) {
|
||||
( (BytecodeLazyAttributeInterceptor) interceptor ).attributeInitialized( propertyName );
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterc
|
|||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.bytecode.spi.NotInstrumentedException;
|
||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
|
@ -41,7 +42,7 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
boolean collectionsInDefaultFetchGroupEnabled,
|
||||
Metadata metadata) {
|
||||
final Class<?> mappedClass = persistentClass.getMappedClass();
|
||||
final boolean enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( mappedClass );
|
||||
final boolean enhancedForLazyLoading = ManagedTypeHelper.isPersistentAttributeInterceptableType( mappedClass );
|
||||
final LazyAttributesMetadata lazyAttributesMetadata = enhancedForLazyLoading
|
||||
? LazyAttributesMetadata.from( persistentClass, true, collectionsInDefaultFetchGroupEnabled, metadata )
|
||||
: LazyAttributesMetadata.nonEnhanced( persistentClass.getEntityName() );
|
||||
|
@ -141,15 +142,13 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
|
||||
// first, instantiate the entity instance to use as the proxy
|
||||
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) persister.instantiate(
|
||||
final PersistentAttributeInterceptable entity = ManagedTypeHelper.asPersistentAttributeInterceptable( persister.instantiate(
|
||||
identifier,
|
||||
session
|
||||
);
|
||||
) );
|
||||
|
||||
// clear the fields that are marked as dirty in the dirtiness tracker
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
ManagedTypeHelper.processIfSelfDirtinessTracker( entity, BytecodeEnhancementMetadataPojoImpl::clearDirtyAttributes );
|
||||
// add the entity (proxy) instance to the PC
|
||||
persistenceContext.addEnhancedProxy( entityKey, entity );
|
||||
|
||||
|
@ -181,6 +180,10 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
return entity;
|
||||
}
|
||||
|
||||
private static void clearDirtyAttributes(final SelfDirtinessTracker entity) {
|
||||
entity.$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyAttributeLoadingInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
|
@ -248,7 +251,7 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
);
|
||||
}
|
||||
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
ManagedTypeHelper.asPersistentAttributeInterceptable( entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -267,7 +270,7 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
);
|
||||
}
|
||||
|
||||
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
|
||||
final PersistentAttributeInterceptor interceptor = ManagedTypeHelper.asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor == null ) {
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue