HHH-11820 - Simplify dirty tracking on entities without collections [bytebuddy]

This commit is contained in:
barreiro 2017-07-25 02:45:00 +01:00 committed by Gail Badner
parent c392d20dec
commit d0e7fab351
2 changed files with 101 additions and 42 deletions

View File

@ -14,6 +14,7 @@ import java.util.Map;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker; import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker; import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
import org.hibernate.bytecode.enhance.internal.tracker.NoopCollectionTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleCollectionTracker; import org.hibernate.bytecode.enhance.internal.tracker.SimpleCollectionTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker; import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
import org.hibernate.bytecode.enhance.spi.CollectionTracker; import org.hibernate.bytecode.enhance.spi.CollectionTracker;
@ -83,7 +84,23 @@ class CodeTemplates {
} }
} }
static class AreCollectionFieldsDirty { static class GetDirtyAttributesWithoutCollections {
@Advice.OnMethodExit
static void $$_hibernate_getDirtyAttributes(
@Advice.Return(readOnly = false) String[] returned,
@Advice.FieldValue(value = EnhancerConstants.TRACKER_FIELD_NAME) DirtyTracker $$_hibernate_tracker) {
returned = $$_hibernate_tracker == null ? new String[0] : $$_hibernate_tracker.get();
}
}
static class GetCollectionTrackerWithoutCollections {
@Advice.OnMethodExit
static void $$_hibernate_getCollectionTracker( @Advice.Return(readOnly = false) CollectionTracker returned) {
returned = NoopCollectionTracker.INSTANCE;
}
}
static class AreFieldsDirty {
@Advice.OnMethodExit @Advice.OnMethodExit
static void $$_hibernate_hasDirtyAttributes( static void $$_hibernate_hasDirtyAttributes(
@Advice.This ExtendedSelfDirtinessTracker self, @Advice.This ExtendedSelfDirtinessTracker self,
@ -93,6 +110,15 @@ class CodeTemplates {
} }
} }
static class AreFieldsDirtyWithoutCollections {
@Advice.OnMethodExit
static void $$_hibernate_hasDirtyAttributes(
@Advice.Return(readOnly = false) boolean returned,
@Advice.FieldValue(value = EnhancerConstants.TRACKER_FIELD_NAME) DirtyTracker $$_hibernate_tracker) {
returned = $$_hibernate_tracker != null && !$$_hibernate_tracker.isEmpty();
}
}
static class ClearDirtyAttributes { static class ClearDirtyAttributes {
@Advice.OnMethodEnter @Advice.OnMethodEnter
static void $$_hibernate_clearDirtyAttributes( static void $$_hibernate_clearDirtyAttributes(
@ -105,6 +131,16 @@ class CodeTemplates {
} }
} }
static class ClearDirtyAttributesWithoutCollections {
@Advice.OnMethodEnter
static void $$_hibernate_clearDirtyAttributes(
@Advice.FieldValue(value = EnhancerConstants.TRACKER_FIELD_NAME) DirtyTracker $$_hibernate_tracker) {
if ( $$_hibernate_tracker != null ) {
$$_hibernate_tracker.clear();
}
}
}
static class SuspendDirtyTracking { static class SuspendDirtyTracking {
@Advice.OnMethodEnter @Advice.OnMethodEnter
static void $$_hibernate_suspendDirtyTracking( static void $$_hibernate_suspendDirtyTracking(

View File

@ -35,6 +35,7 @@ import org.hibernate.engine.spi.ManagedEntity;
import org.hibernate.engine.spi.ManagedMappedSuperclass; import org.hibernate.engine.spi.ManagedMappedSuperclass;
import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
@ -58,6 +59,7 @@ import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.StubMethod; import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.pool.TypePool; import net.bytebuddy.pool.TypePool;
import static net.bytebuddy.matcher.ElementMatchers.isDefaultFinalizer;
import static net.bytebuddy.matcher.ElementMatchers.isGetter; import static net.bytebuddy.matcher.ElementMatchers.isGetter;
public class EnhancerImpl implements Enhancer { public class EnhancerImpl implements Enhancer {
@ -95,7 +97,7 @@ public class EnhancerImpl implements Enhancer {
try { try {
final TypeDescription managedCtClass = classPool.describe( className ).resolve(); final TypeDescription managedCtClass = classPool.describe( className ).resolve();
DynamicType.Builder<?> builder = doEnhance( DynamicType.Builder<?> builder = doEnhance(
new ByteBuddy().with( TypeValidation.DISABLED ).redefine( managedCtClass, ClassFileLocator.Simple.of( className, originalBytes ) ), new ByteBuddy().ignore( isDefaultFinalizer() ).with( TypeValidation.DISABLED ).redefine( managedCtClass, ClassFileLocator.Simple.of( className, originalBytes ) ),
managedCtClass managedCtClass
); );
if ( builder == null ) { if ( builder == null ) {
@ -161,6 +163,26 @@ public class EnhancerImpl implements Enhancer {
builder = addInterceptorHandling( builder, managedCtClass ); builder = addInterceptorHandling( builder, managedCtClass );
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
if ( collectCollectionFields( managedCtClass ).isEmpty() ) {
builder = builder.implement( SelfDirtinessTracker.class )
.defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldManifestation.TRANSIENT, Visibility.PRIVATE )
.annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() )
.defineMethod( EnhancerConstants.TRACKER_CHANGER_NAME, void.class, Visibility.PUBLIC )
.withParameters( String.class )
.intercept( Advice.to( CodeTemplates.TrackChange.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_GET_NAME, String[].class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.GetDirtyAttributesWithoutCollections.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_HAS_CHANGED_NAME, boolean.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.AreFieldsDirtyWithoutCollections.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_CLEAR_NAME, void.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.ClearDirtyAttributesWithoutCollections.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_SUSPEND_NAME, void.class, Visibility.PUBLIC )
.withParameters( boolean.class )
.intercept( Advice.to( CodeTemplates.SuspendDirtyTracking.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_COLLECTION_GET_NAME, CollectionTracker.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.GetCollectionTrackerWithoutCollections.class ).wrap( StubMethod.INSTANCE ) );
}
else {
builder = builder.implement( ExtendedSelfDirtinessTracker.class ) builder = builder.implement( ExtendedSelfDirtinessTracker.class )
.defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldManifestation.TRANSIENT, Visibility.PRIVATE ) .defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldManifestation.TRANSIENT, Visibility.PRIVATE )
.annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() ) .annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() )
@ -172,7 +194,7 @@ public class EnhancerImpl implements Enhancer {
.defineMethod( EnhancerConstants.TRACKER_GET_NAME, String[].class, Visibility.PUBLIC ) .defineMethod( EnhancerConstants.TRACKER_GET_NAME, String[].class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.GetDirtyAttributes.class ).wrap( StubMethod.INSTANCE ) ) .intercept( Advice.to( CodeTemplates.GetDirtyAttributes.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_HAS_CHANGED_NAME, boolean.class, Visibility.PUBLIC ) .defineMethod( EnhancerConstants.TRACKER_HAS_CHANGED_NAME, boolean.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.AreCollectionFieldsDirty.class ).wrap( StubMethod.INSTANCE ) ) .intercept( Advice.to( CodeTemplates.AreFieldsDirty.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_CLEAR_NAME, void.class, Visibility.PUBLIC ) .defineMethod( EnhancerConstants.TRACKER_CLEAR_NAME, void.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.ClearDirtyAttributes.class ).wrap( StubMethod.INSTANCE ) ) .intercept( Advice.to( CodeTemplates.ClearDirtyAttributes.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_SUSPEND_NAME, void.class, Visibility.PUBLIC ) .defineMethod( EnhancerConstants.TRACKER_SUSPEND_NAME, void.class, Visibility.PUBLIC )
@ -183,7 +205,6 @@ public class EnhancerImpl implements Enhancer {
Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE; Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE;
for ( FieldDescription collectionField : collectCollectionFields( managedCtClass ) ) { for ( FieldDescription collectionField : collectCollectionFields( managedCtClass ) ) {
if ( !enhancementContext.isMappedCollection( collectionField ) ) {
if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) { if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) {
isDirty = Advice.withCustomMapping() isDirty = Advice.withCustomMapping()
.bind( CodeTemplates.FieldName.class, collectionField.getName() ) .bind( CodeTemplates.FieldName.class, collectionField.getName() )
@ -219,7 +240,6 @@ public class EnhancerImpl implements Enhancer {
.wrap( clearDirtyNames ); .wrap( clearDirtyNames );
} }
} }
}
if ( enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) { if ( enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) {
clearDirtyNames = Advice.to( CodeTemplates.InitializeLazyAttributeLoadingInterceptor.class ).wrap( clearDirtyNames ); clearDirtyNames = Advice.to( CodeTemplates.InitializeLazyAttributeLoadingInterceptor.class ).wrap( clearDirtyNames );
@ -236,6 +256,7 @@ public class EnhancerImpl implements Enhancer {
.withParameters( LazyAttributeLoadingInterceptor.class ) .withParameters( LazyAttributeLoadingInterceptor.class )
.intercept( clearDirtyNames ); .intercept( clearDirtyNames );
} }
}
return transformer.applyTo( builder, false ); return transformer.applyTo( builder, false );
} }
@ -340,7 +361,7 @@ public class EnhancerImpl implements Enhancer {
if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) { if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) {
continue; continue;
} }
if ( enhancementContext.isPersistentField( ctField ) ) { if ( enhancementContext.isPersistentField( ctField ) && !enhancementContext.isMappedCollection( ctField ) ) {
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) { if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
collectionList.add( ctField ); collectionList.add( ctField );
} }
@ -368,12 +389,14 @@ public class EnhancerImpl implements Enhancer {
List<FieldDescription> collectionList = new ArrayList<FieldDescription>(); List<FieldDescription> collectionList = new ArrayList<FieldDescription>();
for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) { for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) {
if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) { if ( !Modifier.isStatic( ctField.getModifiers() ) ) {
if ( enhancementContext.isPersistentField( ctField ) && !enhancementContext.isMappedCollection( ctField ) ) {
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) { if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
collectionList.add( ctField ); collectionList.add( ctField );
} }
} }
} }
}
collectionList.addAll( collectInheritCollectionFields( managedCtSuperclass ) ); collectionList.addAll( collectInheritCollectionFields( managedCtSuperclass ) );
return collectionList; return collectionList;
} }