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.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
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.SimpleFieldTracker;
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
static void $$_hibernate_hasDirtyAttributes(
@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 {
@Advice.OnMethodEnter
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 {
@Advice.OnMethodEnter
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.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
@ -58,6 +59,7 @@ import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.pool.TypePool;
import static net.bytebuddy.matcher.ElementMatchers.isDefaultFinalizer;
import static net.bytebuddy.matcher.ElementMatchers.isGetter;
public class EnhancerImpl implements Enhancer {
@ -95,7 +97,7 @@ public class EnhancerImpl implements Enhancer {
try {
final TypeDescription managedCtClass = classPool.describe( className ).resolve();
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
);
if ( builder == null ) {
@ -161,29 +163,48 @@ public class EnhancerImpl implements Enhancer {
builder = addInterceptorHandling( builder, managedCtClass );
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
builder = builder.implement( ExtendedSelfDirtinessTracker.class )
.defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldManifestation.TRANSIENT, Visibility.PRIVATE )
.annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() )
.defineField( EnhancerConstants.TRACKER_COLLECTION_NAME, CollectionTracker.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.GetDirtyAttributes.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_HAS_CHANGED_NAME, boolean.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.AreCollectionFieldsDirty.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_CLEAR_NAME, void.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.ClearDirtyAttributes.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( FieldAccessor.ofField( EnhancerConstants.TRACKER_COLLECTION_NAME ) );
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 )
.defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldManifestation.TRANSIENT, Visibility.PRIVATE )
.annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() )
.defineField( EnhancerConstants.TRACKER_COLLECTION_NAME, CollectionTracker.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.GetDirtyAttributes.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_HAS_CHANGED_NAME, boolean.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.AreFieldsDirty.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( EnhancerConstants.TRACKER_CLEAR_NAME, void.class, Visibility.PUBLIC )
.intercept( Advice.to( CodeTemplates.ClearDirtyAttributes.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( FieldAccessor.ofField( EnhancerConstants.TRACKER_COLLECTION_NAME ) );
Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE;
for ( FieldDescription collectionField : collectCollectionFields( managedCtClass ) ) {
if ( !enhancementContext.isMappedCollection( collectionField ) ) {
Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE;
for ( FieldDescription collectionField : collectCollectionFields( managedCtClass ) ) {
if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) {
isDirty = Advice.withCustomMapping()
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
@ -219,22 +240,22 @@ public class EnhancerImpl implements Enhancer {
.wrap( clearDirtyNames );
}
}
}
if ( enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) {
clearDirtyNames = Advice.to( CodeTemplates.InitializeLazyAttributeLoadingInterceptor.class ).wrap( clearDirtyNames );
}
if ( enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) {
clearDirtyNames = Advice.to( CodeTemplates.InitializeLazyAttributeLoadingInterceptor.class ).wrap( clearDirtyNames );
}
builder = builder.defineMethod( EnhancerConstants.TRACKER_COLLECTION_CHANGED_NAME, boolean.class, Visibility.PUBLIC )
.intercept( isDirty )
.defineMethod( EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME, void.class, Visibility.PUBLIC )
.withParameters( DirtyTracker.class )
.intercept( getDirtyNames )
.defineMethod( EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME, void.class, Visibility.PUBLIC )
.intercept( Advice.withCustomMapping().to( CodeTemplates.ClearDirtyCollectionNames.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( ExtendedSelfDirtinessTracker.REMOVE_DIRTY_FIELDS_NAME, void.class, Visibility.PUBLIC )
.withParameters( LazyAttributeLoadingInterceptor.class )
.intercept( clearDirtyNames );
builder = builder.defineMethod( EnhancerConstants.TRACKER_COLLECTION_CHANGED_NAME, boolean.class, Visibility.PUBLIC )
.intercept( isDirty )
.defineMethod( EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME, void.class, Visibility.PUBLIC )
.withParameters( DirtyTracker.class )
.intercept( getDirtyNames )
.defineMethod( EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME, void.class, Visibility.PUBLIC )
.intercept( Advice.withCustomMapping().to( CodeTemplates.ClearDirtyCollectionNames.class ).wrap( StubMethod.INSTANCE ) )
.defineMethod( ExtendedSelfDirtinessTracker.REMOVE_DIRTY_FIELDS_NAME, void.class, Visibility.PUBLIC )
.withParameters( LazyAttributeLoadingInterceptor.class )
.intercept( clearDirtyNames );
}
}
return transformer.applyTo( builder, false );
@ -340,7 +361,7 @@ public class EnhancerImpl implements Enhancer {
if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) {
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 ) ) {
collectionList.add( ctField );
}
@ -368,9 +389,11 @@ public class EnhancerImpl implements Enhancer {
List<FieldDescription> collectionList = new ArrayList<FieldDescription>();
for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) {
if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) {
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
collectionList.add( 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 ) ) {
collectionList.add( ctField );
}
}
}
}