From 4ec71218e957b19fe838a1cdc2722f11944d9c51 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 13 Nov 2018 16:08:50 +0100 Subject: [PATCH] HHH-13097 Cache the annotations resolution --- .../BiDirectionalAssociationHandler.java | 50 +++--- .../ByteBuddyEnhancementContext.java | 36 ++-- .../internal/bytebuddy/EnhancerImpl.java | 157 +++++++++++++----- .../bytebuddy/FieldAccessEnhancer.java | 17 +- .../bytebuddy/FieldReaderAppender.java | 11 +- .../bytebuddy/FieldWriterAppender.java | 3 +- .../bytebuddy/InlineDirtyCheckingHandler.java | 15 +- .../PersistentAttributeTransformer.java | 52 +++--- .../bytebuddy/UnloadedFieldDescription.java | 27 --- .../bytebuddy/UnloadedTypeDescription.java | 1 - 10 files changed, 203 insertions(+), 166 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedFieldDescription.java diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/BiDirectionalAssociationHandler.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/BiDirectionalAssociationHandler.java index 63af04277e..d5e35473c6 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/BiDirectionalAssociationHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/BiDirectionalAssociationHandler.java @@ -17,6 +17,7 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancementException; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.internal.CoreLogging; @@ -43,7 +44,7 @@ final class BiDirectionalAssociationHandler implements Implementation { static Implementation wrap( TypeDescription managedCtClass, ByteBuddyEnhancementContext enhancementContext, - FieldDescription persistentField, + AnnotatedFieldDescription persistentField, Implementation implementation) { if ( !enhancementContext.doBiDirectionalAssociationManagement( persistentField ) ) { return implementation; @@ -69,17 +70,17 @@ final class BiDirectionalAssociationHandler implements Implementation { .getType() .asErasure(); - if ( EnhancerImpl.isAnnotationPresent( persistentField, OneToOne.class ) ) { + if ( persistentField.hasAnnotation( OneToOne.class ) ) { implementation = Advice.withCustomMapping() - .bind( CodeTemplates.FieldValue.class, persistentField ) + .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.OneToOneHandler.class ) .wrap( implementation ); } - if ( EnhancerImpl.isAnnotationPresent( persistentField, OneToMany.class ) ) { + if ( persistentField.hasAnnotation( OneToMany.class ) ) { implementation = Advice.withCustomMapping() - .bind( CodeTemplates.FieldValue.class, persistentField ) + .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( persistentField.getType().asErasure().isAssignableTo( Map.class ) ? CodeTemplates.OneToManyOnMapHandler.class @@ -87,15 +88,15 @@ final class BiDirectionalAssociationHandler implements Implementation { .wrap( implementation ); } - if ( EnhancerImpl.isAnnotationPresent( persistentField, ManyToOne.class ) ) { + if ( persistentField.hasAnnotation( ManyToOne.class ) ) { implementation = Advice.withCustomMapping() - .bind( CodeTemplates.FieldValue.class, persistentField ) + .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.ManyToOneHandler.class ) .wrap( implementation ); } - if ( EnhancerImpl.isAnnotationPresent( persistentField, ManyToMany.class ) ) { + if ( persistentField.hasAnnotation( ManyToMany.class ) ) { if ( persistentField.getType().asErasure().isAssignableTo( Map.class ) || targetType.isAssignableTo( Map.class ) ) { log.infof( @@ -107,7 +108,7 @@ final class BiDirectionalAssociationHandler implements Implementation { } implementation = Advice.withCustomMapping() - .bind( CodeTemplates.FieldValue.class, persistentField ) + .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.MappedBy.class, mappedBy ) .to( CodeTemplates.ManyToManyHandler.class ) .wrap( implementation ); @@ -116,12 +117,12 @@ final class BiDirectionalAssociationHandler implements Implementation { return new BiDirectionalAssociationHandler( implementation, targetEntity, targetType, mappedBy ); } - public static TypeDescription getTargetEntityClass(TypeDescription managedCtClass, FieldDescription persistentField) { + public static TypeDescription getTargetEntityClass(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { try { - AnnotationDescription.Loadable oto = EnhancerImpl.getAnnotation( persistentField, OneToOne.class ); - AnnotationDescription.Loadable otm = EnhancerImpl.getAnnotation( persistentField, OneToMany.class ); - AnnotationDescription.Loadable mto = EnhancerImpl.getAnnotation( persistentField, ManyToOne.class ); - AnnotationDescription.Loadable mtm = EnhancerImpl.getAnnotation( persistentField, ManyToMany.class ); + AnnotationDescription.Loadable oto = persistentField.getAnnotation( OneToOne.class ); + AnnotationDescription.Loadable otm = persistentField.getAnnotation( OneToMany.class ); + AnnotationDescription.Loadable mto = persistentField.getAnnotation( ManyToOne.class ); + AnnotationDescription.Loadable mtm = persistentField.getAnnotation( ManyToMany.class ); if ( oto == null && otm == null && mto == null && mtm == null ) { return null; @@ -159,7 +160,7 @@ final class BiDirectionalAssociationHandler implements Implementation { return entityType( target( persistentField ) ); } - private static TypeDescription.Generic target(FieldDescription persistentField) { + private static TypeDescription.Generic target(AnnotatedFieldDescription persistentField) { AnnotationDescription.Loadable access = persistentField.getDeclaringType().asErasure().getDeclaredAnnotations().ofType( Access.class ); if ( access != null && access.loadSilent().value() == AccessType.FIELD ) { return persistentField.getType(); @@ -175,7 +176,7 @@ final class BiDirectionalAssociationHandler implements Implementation { } } - private static String getMappedBy(FieldDescription target, TypeDescription targetEntity, ByteBuddyEnhancementContext context) { + private static String getMappedBy(AnnotatedFieldDescription target, TypeDescription targetEntity, ByteBuddyEnhancementContext context) { String mappedBy = getMappedByNotManyToMany( target ); if ( mappedBy == null || mappedBy.isEmpty() ) { return getMappedByManyToMany( target, targetEntity, context ); @@ -185,19 +186,19 @@ final class BiDirectionalAssociationHandler implements Implementation { } } - private static String getMappedByNotManyToMany(FieldDescription target) { + private static String getMappedByNotManyToMany(AnnotatedFieldDescription target) { try { - AnnotationDescription.Loadable oto = EnhancerImpl.getAnnotation( target, OneToOne.class ); + AnnotationDescription.Loadable oto = target.getAnnotation( OneToOne.class ); if ( oto != null ) { return oto.getValue( new MethodDescription.ForLoadedMethod( OneToOne.class.getDeclaredMethod( "mappedBy" ) ) ).resolve( String.class ); } - AnnotationDescription.Loadable otm = EnhancerImpl.getAnnotation( target, OneToMany.class ); + AnnotationDescription.Loadable otm = target.getAnnotation( OneToMany.class ); if ( otm != null ) { return otm.getValue( new MethodDescription.ForLoadedMethod( OneToMany.class.getDeclaredMethod( "mappedBy" ) ) ).resolve( String.class ); } - AnnotationDescription.Loadable mtm = EnhancerImpl.getAnnotation( target, ManyToMany.class ); + AnnotationDescription.Loadable mtm = target.getAnnotation( ManyToMany.class ); if ( mtm != null ) { return mtm.getValue( new MethodDescription.ForLoadedMethod( ManyToMany.class.getDeclaredMethod( "mappedBy" ) ) ).resolve( String.class ); } @@ -208,11 +209,12 @@ final class BiDirectionalAssociationHandler implements Implementation { return null; } - private static String getMappedByManyToMany(FieldDescription target, TypeDescription targetEntity, ByteBuddyEnhancementContext context) { + private static String getMappedByManyToMany(AnnotatedFieldDescription target, TypeDescription targetEntity, ByteBuddyEnhancementContext context) { for ( FieldDescription f : targetEntity.getDeclaredFields() ) { - if ( context.isPersistentField( f ) - && target.getName().equals( getMappedByNotManyToMany( f ) ) - && target.getDeclaringType().asErasure().isAssignableTo( entityType( f.getType() ) ) ) { + AnnotatedFieldDescription annotatedF = new AnnotatedFieldDescription( f ); + if ( context.isPersistentField( annotatedF ) + && target.getName().equals( getMappedByNotManyToMany( annotatedF ) ) + && target.getDeclaringType().asErasure().isAssignableTo( entityType( annotatedF.getType() ) ) ) { log.debugf( "mappedBy association for field [%s#%s] is [%s#%s]", target.getDeclaringType().asErasure().getName(), diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/ByteBuddyEnhancementContext.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/ByteBuddyEnhancementContext.java index 09a6e30620..40df641c4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/ByteBuddyEnhancementContext.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/ByteBuddyEnhancementContext.java @@ -6,10 +6,9 @@ */ package org.hibernate.bytecode.enhance.internal.bytebuddy; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancementContext; -import org.hibernate.bytecode.enhance.spi.UnloadedField; -import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.type.TypeDescription; class ByteBuddyEnhancementContext { @@ -36,10 +35,6 @@ class ByteBuddyEnhancementContext { return enhancementContext.isMappedSuperclassClass( new UnloadedTypeDescription( classDescriptor ) ); } - public boolean doBiDirectionalAssociationManagement(FieldDescription field) { - return enhancementContext.doBiDirectionalAssociationManagement( new UnloadedFieldDescription( field ) ); - } - public boolean doDirtyCheckingInline(TypeDescription classDescriptor) { return enhancementContext.doDirtyCheckingInline( new UnloadedTypeDescription( classDescriptor ) ); } @@ -52,28 +47,23 @@ class ByteBuddyEnhancementContext { return enhancementContext.hasLazyLoadableAttributes( new UnloadedTypeDescription( classDescriptor ) ); } - public boolean isPersistentField(FieldDescription ctField) { - return enhancementContext.isPersistentField( new UnloadedFieldDescription( ctField ) ); + public boolean isPersistentField(AnnotatedFieldDescription field) { + return enhancementContext.isPersistentField( field ); } - public FieldDescription[] order(FieldDescription[] persistentFields) { - UnloadedField[] unloadedFields = new UnloadedField[persistentFields.length]; - for ( int i = 0; i < unloadedFields.length; i++ ) { - unloadedFields[i] = new UnloadedFieldDescription( persistentFields[i] ); - } - UnloadedField[] ordered = enhancementContext.order( unloadedFields ); - FieldDescription[] orderedFields = new FieldDescription[persistentFields.length]; - for ( int i = 0; i < orderedFields.length; i++ ) { - orderedFields[i] = ( (UnloadedFieldDescription) ordered[i] ).fieldDescription; - } - return orderedFields; + public AnnotatedFieldDescription[] order(AnnotatedFieldDescription[] persistentFields) { + return (AnnotatedFieldDescription[]) enhancementContext.order( persistentFields ); } - public boolean isLazyLoadable(FieldDescription field) { - return enhancementContext.isLazyLoadable( new UnloadedFieldDescription( field ) ); + public boolean isLazyLoadable(AnnotatedFieldDescription field) { + return enhancementContext.isLazyLoadable( field ); } - public boolean isMappedCollection(FieldDescription field) { - return enhancementContext.isMappedCollection( new UnloadedFieldDescription( field ) ); + public boolean isMappedCollection(AnnotatedFieldDescription field) { + return enhancementContext.isMappedCollection( field ); + } + + public boolean doBiDirectionalAssociationManagement(AnnotatedFieldDescription field) { + return enhancementContext.doBiDirectionalAssociationManagement( field ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java index 946c0d41ac..992bf8d84b 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java @@ -28,6 +28,7 @@ import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.enhance.spi.EnhancementException; import org.hibernate.bytecode.enhance.spi.Enhancer; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; +import org.hibernate.bytecode.enhance.spi.UnloadedField; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState; import org.hibernate.engine.spi.CompositeOwner; @@ -46,13 +47,16 @@ import org.hibernate.internal.CoreMessageLogger; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.field.FieldDescription.InDefinedShape; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.modifier.FieldPersistence; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeDescription.Generic; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.scaffold.MethodGraph; @@ -60,6 +64,7 @@ import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.StubMethod; +import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.pool.TypePool; public class EnhancerImpl implements Enhancer { @@ -182,7 +187,9 @@ public class EnhancerImpl implements Enhancer { builder = addInterceptorHandling( builder, managedCtClass ); if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { - if ( collectCollectionFields( managedCtClass ).isEmpty() ) { + List collectionFields = collectCollectionFields( managedCtClass ); + + if ( collectionFields.isEmpty() ) { builder = builder.implement( SelfDirtinessTracker.class ) .defineField( EnhancerConstants.TRACKER_FIELD_NAME, DirtyTracker.class, FieldPersistence.TRANSIENT, Visibility.PRIVATE ) .annotateField( AnnotationDescription.Builder.ofType( Transient.class ).build() ) @@ -223,38 +230,38 @@ public class EnhancerImpl implements Enhancer { .intercept( FieldAccessor.ofField( EnhancerConstants.TRACKER_COLLECTION_NAME ) ); Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE; - for ( FieldDescription collectionField : collectCollectionFields( managedCtClass ) ) { + for ( AnnotatedFieldDescription collectionField : collectionFields ) { if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) { isDirty = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) - .bind( CodeTemplates.FieldValue.class, collectionField ) + .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapAreCollectionFieldsDirty.class, adviceLocator ) .wrap( isDirty ); getDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) - .bind( CodeTemplates.FieldValue.class, collectionField ) + .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapGetCollectionFieldDirtyNames.class, adviceLocator ) .wrap( getDirtyNames ); clearDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) - .bind( CodeTemplates.FieldValue.class, collectionField ) + .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.MapGetCollectionClearDirtyNames.class, adviceLocator ) .wrap( clearDirtyNames ); } else { isDirty = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) - .bind( CodeTemplates.FieldValue.class, collectionField ) + .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionAreCollectionFieldsDirty.class, adviceLocator ) .wrap( isDirty ); getDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) - .bind( CodeTemplates.FieldValue.class, collectionField ) + .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionGetCollectionFieldDirtyNames.class, adviceLocator ) .wrap( getDirtyNames ); clearDirtyNames = Advice.withCustomMapping() .bind( CodeTemplates.FieldName.class, collectionField.getName() ) - .bind( CodeTemplates.FieldValue.class, collectionField ) + .bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() ) .to( CodeTemplates.CollectionGetCollectionClearDirtyNames.class, adviceLocator ) .wrap( clearDirtyNames ); } @@ -375,17 +382,18 @@ public class EnhancerImpl implements Enhancer { .intercept( FieldAccessor.ofField( fieldName ) ); } - private List collectCollectionFields(TypeDescription managedCtClass) { - List collectionList = new ArrayList<>(); + private List collectCollectionFields(TypeDescription managedCtClass) { + List collectionList = new ArrayList<>(); for ( FieldDescription ctField : managedCtClass.getDeclaredFields() ) { // skip static fields and skip fields added by enhancement if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) { continue; } - if ( enhancementContext.isPersistentField( ctField ) && !enhancementContext.isMappedCollection( ctField ) ) { + AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); + if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) { if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) { - collectionList.add( ctField ); + collectionList.add( annotatedField ); } } } @@ -399,7 +407,7 @@ public class EnhancerImpl implements Enhancer { return collectionList; } - private Collection collectInheritCollectionFields(TypeDefinition managedCtClass) { + private Collection collectInheritCollectionFields(TypeDefinition managedCtClass) { TypeDefinition managedCtSuperclass = managedCtClass.getSuperClass(); if ( managedCtSuperclass == null || managedCtSuperclass.represents( Object.class ) ) { return Collections.emptyList(); @@ -408,13 +416,14 @@ public class EnhancerImpl implements Enhancer { if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass.asErasure() ) ) { return collectInheritCollectionFields( managedCtSuperclass.asErasure() ); } - List collectionList = new ArrayList(); + List collectionList = new ArrayList<>(); for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) { if ( !Modifier.isStatic( ctField.getModifiers() ) ) { - if ( enhancementContext.isPersistentField( ctField ) && !enhancementContext.isMappedCollection( ctField ) ) { + AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); + if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) { if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) { - collectionList.add( ctField ); + collectionList.add( annotatedField ); } } } @@ -427,41 +436,15 @@ public class EnhancerImpl implements Enhancer { return Character.toUpperCase( value.charAt( 0 ) ) + value.substring( 1 ); } - static boolean isAnnotationPresent(FieldDescription fieldDescription, Class type) { - return getAnnotation( fieldDescription, type ) != null; - } - - static AnnotationDescription.Loadable getAnnotation(FieldDescription fieldDescription, Class type) { - AnnotationDescription.Loadable access = fieldDescription.getDeclaringType().asErasure().getDeclaredAnnotations().ofType( Access.class ); - if ( access != null && access.loadSilent().value() == AccessType.PROPERTY ) { - MethodDescription getter = getterOf( fieldDescription ); - if ( getter == null ) { - return fieldDescription.getDeclaredAnnotations().ofType( type ); - } - else { - return getter.getDeclaredAnnotations().ofType( type ); - } - } - else if ( access != null && access.loadSilent().value() == AccessType.FIELD ) { - return fieldDescription.getDeclaredAnnotations().ofType( type ); - } - else { - MethodDescription getter = getterOf( fieldDescription ); - if ( getter != null ) { - AnnotationDescription.Loadable annotationDescription = getter.getDeclaredAnnotations().ofType( type ); - if ( annotationDescription != null ) { - return annotationDescription; - } - } - return fieldDescription.getDeclaredAnnotations().ofType( type ); - } + static MethodDescription getterOf(AnnotatedFieldDescription persistentField) { + return getterOf( persistentField.fieldDescription ); } static MethodDescription getterOf(FieldDescription persistentField) { MethodList methodList = MethodGraph.Compiler.DEFAULT.compile( persistentField.getDeclaringType().asErasure() ) .listNodes() .asMethodList() - .filter( isGetter(persistentField.getName() ) ); + .filter( isGetter( persistentField.getName() ) ); if ( methodList.size() == 1 ) { return methodList.getOnly(); } @@ -469,4 +452,88 @@ public class EnhancerImpl implements Enhancer { return null; } } + + static class AnnotatedFieldDescription implements UnloadedField { + + private final FieldDescription fieldDescription; + + private AnnotationList annotations; + + AnnotatedFieldDescription(FieldDescription fieldDescription) { + this.fieldDescription = fieldDescription; + } + + @Override + public boolean hasAnnotation(Class annotationType) { + return getAnnotations().isAnnotationPresent( annotationType ); + } + + AnnotationDescription.Loadable getAnnotation(Class annotationType) { + return getAnnotations().ofType( annotationType ); + } + + String getName() { + return fieldDescription.getName(); + } + + TypeDefinition getDeclaringType() { + return fieldDescription.getDeclaringType(); + } + + Generic getType() { + return fieldDescription.getType(); + } + + InDefinedShape asDefined() { + return fieldDescription.asDefined(); + } + + String getDescriptor() { + return fieldDescription.getDescriptor(); + } + + boolean isVisibleTo(TypeDescription typeDescription) { + return fieldDescription.isVisibleTo( typeDescription ); + } + + FieldDescription getFieldDescription() { + return fieldDescription; + } + + private AnnotationList getAnnotations() { + if ( annotations == null ) { + annotations = doGetAnnotations( fieldDescription ); + } + return annotations; + } + + private static AnnotationList doGetAnnotations(FieldDescription fieldDescription) { + AnnotationDescription.Loadable access = fieldDescription.getDeclaringType().asErasure() + .getDeclaredAnnotations().ofType( Access.class ); + if ( access != null && access.loadSilent().value() == AccessType.PROPERTY ) { + MethodDescription getter = getterOf( fieldDescription ); + if ( getter == null ) { + return fieldDescription.getDeclaredAnnotations(); + } + else { + return getter.getDeclaredAnnotations(); + } + } + else if ( access != null && access.loadSilent().value() == AccessType.FIELD ) { + return fieldDescription.getDeclaredAnnotations(); + } + else { + MethodDescription getter = getterOf( fieldDescription ); + + // Note that the order here is important + List annotationDescriptions = new ArrayList<>(); + if ( getter != null ) { + annotationDescriptions.addAll( getter.getDeclaredAnnotations() ); + } + annotationDescriptions.addAll( fieldDescription.getDeclaredAnnotations() ); + + return fieldDescription.getDeclaredAnnotations(); + } + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java index 796d324102..d5f2020ca7 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java @@ -6,16 +6,18 @@ */ package org.hibernate.bytecode.enhance.internal.bytebuddy; +import static net.bytebuddy.matcher.ElementMatchers.hasDescriptor; +import static net.bytebuddy.matcher.ElementMatchers.named; + import javax.persistence.Id; -import net.bytebuddy.description.method.MethodList; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancementException; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import net.bytebuddy.asm.AsmVisitorWrapper; -import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; @@ -25,9 +27,6 @@ import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Type; import net.bytebuddy.pool.TypePool; -import static net.bytebuddy.matcher.ElementMatchers.hasDescriptor; -import static net.bytebuddy.matcher.ElementMatchers.named; - import java.util.Objects; final class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper { @@ -63,13 +62,13 @@ final class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods. return; } - FieldDescription field = findField( owner, name, desc ); + AnnotatedFieldDescription field = findField( owner, name, desc ); if ( ( enhancementContext.isEntityClass( field.getDeclaringType().asErasure() ) || enhancementContext.isCompositeClass( field.getDeclaringType().asErasure() ) ) && !field.getType().asErasure().equals( managedCtClass ) && enhancementContext.isPersistentField( field ) - && !EnhancerImpl.isAnnotationPresent( field, Id.class ) + && !field.hasAnnotation( Id.class ) && !field.getName().equals( "this$0" ) ) { log.debugf( @@ -110,7 +109,7 @@ final class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods. }; } - private FieldDescription findField(String owner, String name, String desc) { + private AnnotatedFieldDescription findField(String owner, String name, String desc) { //Classpool#describe does not accept '/' in the description name as it expects a class name final String cleanedOwner = owner.replace( '/', '.' ); final TypePool.Resolution resolution = classPool.describe( cleanedOwner ); @@ -130,7 +129,7 @@ final class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods. ); throw new EnhancementException( msg ); } - return fields.getOnly(); + return new AnnotatedFieldDescription( fields.getOnly() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java index 9163f91c1d..56b12d8eac 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java @@ -8,6 +8,7 @@ package org.hibernate.bytecode.enhance.internal.bytebuddy; import java.util.Objects; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.engine.spi.PersistentAttributeInterceptor; @@ -26,17 +27,17 @@ abstract class FieldReaderAppender implements ByteCodeAppender { protected final TypeDescription managedCtClass; - protected final FieldDescription persistentField; + protected final AnnotatedFieldDescription persistentField; protected final FieldDescription.InDefinedShape persistentFieldAsDefined; - private FieldReaderAppender(TypeDescription managedCtClass, FieldDescription persistentField) { + private FieldReaderAppender(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { this.managedCtClass = managedCtClass; this.persistentField = persistentField; this.persistentFieldAsDefined = persistentField.asDefined(); } - static ByteCodeAppender of(TypeDescription managedCtClass, FieldDescription persistentField) { + static ByteCodeAppender of(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { if ( !persistentField.isVisibleTo( managedCtClass ) ) { return new MethodDispatching( managedCtClass, persistentField ); } @@ -119,7 +120,7 @@ abstract class FieldReaderAppender implements ByteCodeAppender { private static class FieldWriting extends FieldReaderAppender { - private FieldWriting(TypeDescription managedCtClass, FieldDescription persistentField) { + private FieldWriting(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { super( managedCtClass, persistentField ); } @@ -146,7 +147,7 @@ abstract class FieldReaderAppender implements ByteCodeAppender { private static class MethodDispatching extends FieldReaderAppender { - private MethodDispatching(TypeDescription managedCtClass, FieldDescription persistentField) { + private MethodDispatching(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { super( managedCtClass, persistentField ); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldWriterAppender.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldWriterAppender.java index 9ab725d62f..d666ae43b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldWriterAppender.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldWriterAppender.java @@ -6,6 +6,7 @@ */ package org.hibernate.bytecode.enhance.internal.bytebuddy; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.engine.spi.PersistentAttributeInterceptor; @@ -31,7 +32,7 @@ abstract class FieldWriterAppender implements ByteCodeAppender { this.persistentFieldAsDefined = persistentFieldAsDefined; } - static ByteCodeAppender of(TypeDescription managedCtClass, FieldDescription persistentField) { + static ByteCodeAppender of(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { if ( !persistentField.isVisibleTo( managedCtClass ) ) { return new MethodDispatching( managedCtClass, persistentField.asDefined() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java index e08cb52318..34e2bb30cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java @@ -8,10 +8,12 @@ package org.hibernate.bytecode.enhance.internal.bytebuddy; import java.util.Collection; import java.util.Objects; + import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.Id; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import net.bytebuddy.ClassFileVersion; @@ -44,25 +46,26 @@ final class InlineDirtyCheckingHandler implements Implementation, ByteCodeAppend static Implementation wrap( TypeDescription managedCtClass, ByteBuddyEnhancementContext enhancementContext, - FieldDescription persistentField, + AnnotatedFieldDescription persistentField, Implementation implementation) { if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { if ( enhancementContext.isCompositeClass( managedCtClass ) ) { implementation = Advice.to( CodeTemplates.CompositeDirtyCheckingHandler.class ).wrap( implementation ); } - else if ( !EnhancerImpl.isAnnotationPresent( persistentField, Id.class ) - && !EnhancerImpl.isAnnotationPresent( persistentField, EmbeddedId.class ) + else if ( !persistentField.hasAnnotation( Id.class ) + && !persistentField.hasAnnotation( EmbeddedId.class ) && !( persistentField.getType().asErasure().isAssignableTo( Collection.class ) && enhancementContext.isMappedCollection( persistentField ) ) ) { - implementation = new InlineDirtyCheckingHandler( implementation, managedCtClass, persistentField.asDefined() ); + implementation = new InlineDirtyCheckingHandler( implementation, managedCtClass, + persistentField.asDefined() ); } if ( enhancementContext.isCompositeClass( persistentField.getType().asErasure() ) - && EnhancerImpl.isAnnotationPresent( persistentField, Embedded.class ) ) { + && persistentField.hasAnnotation( Embedded.class ) ) { implementation = Advice.withCustomMapping() - .bind( CodeTemplates.FieldValue.class, persistentField ) + .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() ) .bind( CodeTemplates.FieldName.class, persistentField.getName() ) .to( CodeTemplates.CompositeFieldDirtyCheckingHandler.class ) .wrap( implementation ); diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java index 543820d4bd..715ceef90a 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java @@ -6,6 +6,9 @@ */ package org.hibernate.bytecode.enhance.internal.bytebuddy; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.not; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -15,14 +18,12 @@ import java.util.Objects; import javax.persistence.Embedded; -import net.bytebuddy.description.field.FieldList; -import net.bytebuddy.description.method.MethodList; +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.engine.spi.CompositeOwner; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; -import net.bytebuddy.ClassFileVersion; import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.AsmVisitorWrapper; import net.bytebuddy.description.field.FieldDescription; @@ -40,9 +41,6 @@ import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Type; import net.bytebuddy.pool.TypePool; -import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; -import static net.bytebuddy.matcher.ElementMatchers.not; - final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper { private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributeTransformer.class ); @@ -53,13 +51,13 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla private final TypePool classPool; - private final FieldDescription[] enhancedFields; + private final AnnotatedFieldDescription[] enhancedFields; private PersistentAttributeTransformer( TypeDescription managedCtClass, ByteBuddyEnhancementContext enhancementContext, TypePool classPool, - FieldDescription[] enhancedFields) { + AnnotatedFieldDescription[] enhancedFields) { this.managedCtClass = managedCtClass; this.enhancementContext = enhancementContext; this.classPool = classPool; @@ -70,14 +68,15 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla TypeDescription managedCtClass, ByteBuddyEnhancementContext enhancementContext, TypePool classPool) { - List persistentFieldList = new ArrayList(); + List persistentFieldList = new ArrayList<>(); for ( FieldDescription ctField : managedCtClass.getDeclaredFields() ) { // skip static fields and skip fields added by enhancement and outer reference in inner classes if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) { continue; } - if ( !ctField.isStatic() && enhancementContext.isPersistentField( ctField ) ) { - persistentFieldList.add( ctField ); + AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); + if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) { + persistentFieldList.add( annotatedField ); } } // HHH-10646 Add fields inherited from @MappedSuperclass @@ -86,12 +85,12 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla persistentFieldList.addAll( collectInheritPersistentFields( managedCtClass, enhancementContext ) ); } - FieldDescription[] orderedFields = enhancementContext.order( persistentFieldList.toArray( new FieldDescription[0] ) ); + AnnotatedFieldDescription[] orderedFields = enhancementContext.order( persistentFieldList.toArray( new AnnotatedFieldDescription[0] ) ); log.debugf( "Persistent fields for entity %s: %s", managedCtClass.getName(), Arrays.toString( orderedFields ) ); return new PersistentAttributeTransformer( managedCtClass, enhancementContext, classPool, orderedFields ); } - private static Collection collectInheritPersistentFields( + private static Collection collectInheritPersistentFields( TypeDefinition managedCtClass, ByteBuddyEnhancementContext enhancementContext) { if ( managedCtClass == null || managedCtClass.represents( Object.class ) ) { @@ -102,15 +101,18 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass.asErasure() ) ) { return collectInheritPersistentFields( managedCtSuperclass, enhancementContext ); } + log.debugf( "Found @MappedSuperclass %s to collectPersistenceFields", managedCtSuperclass ); - List persistentFieldList = new ArrayList(); + + List persistentFieldList = new ArrayList<>(); for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) { if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) { continue; } - if ( !ctField.isStatic() && enhancementContext.isPersistentField( ctField ) ) { - persistentFieldList.add( ctField ); + AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); + if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) { + persistentFieldList.add( annotatedField ); } } persistentFieldList.addAll( collectInheritPersistentFields( managedCtSuperclass, enhancementContext ) ); @@ -157,7 +159,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla } private boolean isEnhanced(String owner, String name, String desc) { - for ( FieldDescription enhancedField : enhancedFields ) { + for ( AnnotatedFieldDescription enhancedField : enhancedFields ) { if ( enhancedField.getName().equals( name ) && enhancedField.getDescriptor().equals( desc ) && enhancedField.getDeclaringType().asErasure().getInternalName().equals( owner ) ) { @@ -171,7 +173,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla boolean compositeOwner = false; builder = builder.visit( new AsmVisitorWrapper.ForDeclaredMethods().invokable( not( nameStartsWith( "$$_hibernate_" ) ), this ) ); - for ( FieldDescription enhancedField : enhancedFields ) { + for ( AnnotatedFieldDescription enhancedField : enhancedFields ) { builder = builder .defineMethod( EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + enhancedField.getName(), @@ -195,7 +197,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla if ( !compositeOwner && !accessor - && EnhancerImpl.isAnnotationPresent( enhancedField, Embedded.class ) + && enhancedField.hasAnnotation( Embedded.class ) && enhancementContext.isCompositeClass( enhancedField.getType().asErasure() ) && enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { compositeOwner = true; @@ -219,7 +221,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla return builder; } - private Implementation fieldReader(FieldDescription enhancedField) { + private Implementation fieldReader(AnnotatedFieldDescription enhancedField) { if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( enhancedField ) ) { if ( enhancedField.getDeclaringType().asErasure().equals( managedCtClass ) ) { return FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() ); @@ -233,7 +235,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla } } - private Implementation fieldWriter(FieldDescription enhancedField) { + private Implementation fieldWriter(AnnotatedFieldDescription enhancedField) { Implementation implementation; if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( enhancedField ) ) { if ( enhancedField.getDeclaringType().asErasure().equals( managedCtClass ) ) { @@ -259,9 +261,9 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla private final TypeDescription managedCtClass; - private final FieldDescription persistentField; + private final AnnotatedFieldDescription persistentField; - private FieldMethodReader(TypeDescription managedCtClass, FieldDescription persistentField) { + private FieldMethodReader(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { this.managedCtClass = managedCtClass; this.persistentField = persistentField; } @@ -289,9 +291,9 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla private final TypeDescription managedCtClass; - private final FieldDescription persistentField; + private final AnnotatedFieldDescription persistentField; - private FieldMethodWriter(TypeDescription managedCtClass, FieldDescription persistentField) { + private FieldMethodWriter(TypeDescription managedCtClass, AnnotatedFieldDescription persistentField) { this.managedCtClass = managedCtClass; this.persistentField = persistentField; } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedFieldDescription.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedFieldDescription.java deleted file mode 100644 index c95915017d..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedFieldDescription.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 . - */ -package org.hibernate.bytecode.enhance.internal.bytebuddy; - -import java.lang.annotation.Annotation; - -import org.hibernate.bytecode.enhance.spi.UnloadedField; - -import net.bytebuddy.description.field.FieldDescription; - -class UnloadedFieldDescription implements UnloadedField { - - final FieldDescription fieldDescription; - - UnloadedFieldDescription(FieldDescription fieldDescription) { - this.fieldDescription = fieldDescription; - } - - @Override - public boolean hasAnnotation(Class annotationType) { - return fieldDescription.getDeclaredAnnotations().isAnnotationPresent( annotationType ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedTypeDescription.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedTypeDescription.java index ef46232691..e2ca1bde11 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedTypeDescription.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/UnloadedTypeDescription.java @@ -9,7 +9,6 @@ package org.hibernate.bytecode.enhance.internal.bytebuddy; import java.lang.annotation.Annotation; import org.hibernate.bytecode.enhance.spi.UnloadedClass; -import org.hibernate.bytecode.enhance.spi.UnloadedField; import net.bytebuddy.description.type.TypeDescription;