Skip to content

Commit

Permalink
HHH-11820 - Simplify dirty tracking on entities without collections […
Browse files Browse the repository at this point in the history
…bytebuddy]
  • Loading branch information
barreiro authored and gbadner committed Sep 12, 2017
1 parent c392d20 commit d0e7fab
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 43 deletions.
Expand Up @@ -14,6 +14,7 @@
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;
Expand Down Expand Up @@ -83,7 +84,23 @@ static class GetDirtyAttributes {
}
}

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,
Expand All @@ -93,6 +110,15 @@ static class AreCollectionFieldsDirty {
}
}

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(
Expand All @@ -105,6 +131,16 @@ static class ClearDirtyAttributes {
}
}

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(
Expand Down
Expand Up @@ -35,6 +35,7 @@
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;

Expand All @@ -58,6 +59,7 @@
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 {
Expand Down Expand Up @@ -95,7 +97,7 @@ public synchronized byte[] enhance(String className, byte[] originalBytes) throw
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 ) {
Expand Down Expand Up @@ -161,29 +163,48 @@ private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDes
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 ) );

Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE;
for ( FieldDescription collectionField : collectCollectionFields( managedCtClass ) ) {
if ( !enhancementContext.isMappedCollection( collectionField ) ) {
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 ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) {
isDirty = Advice.withCustomMapping()
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
Expand Down Expand Up @@ -219,22 +240,22 @@ private DynamicType.Builder<?> doEnhance(DynamicType.Builder<?> builder, TypeDes
.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 );
Expand Down Expand Up @@ -340,7 +361,7 @@ private List<FieldDescription> collectCollectionFields(TypeDescription managedCt
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 );
}
Expand Down Expand Up @@ -368,9 +389,11 @@ private Collection<FieldDescription> collectInheritCollectionFields(TypeDefiniti
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 );
}
}
}
}
Expand Down

0 comments on commit d0e7fab

Please sign in to comment.