HHH-13097 Cache the resolution of the getters

This commit is contained in:
Guillaume Smet 2018-11-13 17:09:15 +01:00 committed by Sanne Grinovero
parent 4ec71218e9
commit 45d5aa7ddf
5 changed files with 94 additions and 38 deletions

View File

@ -9,6 +9,7 @@ package org.hibernate.bytecode.enhance.internal.bytebuddy;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
@ -166,12 +167,12 @@ final class BiDirectionalAssociationHandler implements Implementation {
return persistentField.getType(); return persistentField.getType();
} }
else { else {
MethodDescription getter = EnhancerImpl.getterOf( persistentField ); Optional<MethodDescription> getter = persistentField.getGetter();
if ( getter == null ) { if ( getter.isPresent() ) {
return persistentField.getType(); return getter.get().getReturnType();
} }
else { else {
return getter.getReturnType(); return persistentField.getType();
} }
} }
} }
@ -211,7 +212,7 @@ final class BiDirectionalAssociationHandler implements Implementation {
private static String getMappedByManyToMany(AnnotatedFieldDescription target, TypeDescription targetEntity, ByteBuddyEnhancementContext context) { private static String getMappedByManyToMany(AnnotatedFieldDescription target, TypeDescription targetEntity, ByteBuddyEnhancementContext context) {
for ( FieldDescription f : targetEntity.getDeclaredFields() ) { for ( FieldDescription f : targetEntity.getDeclaredFields() ) {
AnnotatedFieldDescription annotatedF = new AnnotatedFieldDescription( f ); AnnotatedFieldDescription annotatedF = new AnnotatedFieldDescription( context, f );
if ( context.isPersistentField( annotatedF ) if ( context.isPersistentField( annotatedF )
&& target.getName().equals( getMappedByNotManyToMany( annotatedF ) ) && target.getName().equals( getMappedByNotManyToMany( annotatedF ) )
&& target.getDeclaringType().asErasure().isAssignableTo( entityType( annotatedF.getType() ) ) ) { && target.getDeclaringType().asErasure().isAssignableTo( entityType( annotatedF.getType() ) ) ) {

View File

@ -6,15 +6,33 @@
*/ */
package org.hibernate.bytecode.enhance.internal.bytebuddy; package org.hibernate.bytecode.enhance.internal.bytebuddy;
import static net.bytebuddy.matcher.ElementMatchers.isGetter;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.hibernate.MappingException;
import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription;
import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.MethodGraph;
import net.bytebuddy.matcher.ElementMatcher;
class ByteBuddyEnhancementContext { class ByteBuddyEnhancementContext {
private static final ElementMatcher.Junction<MethodDescription> IS_GETTER = isGetter();
private final EnhancementContext enhancementContext; private final EnhancementContext enhancementContext;
private final ConcurrentHashMap<TypeDescription, Map<String, MethodDescription>> getterByTypeMap = new ConcurrentHashMap<>();
ByteBuddyEnhancementContext(EnhancementContext enhancementContext) { ByteBuddyEnhancementContext(EnhancementContext enhancementContext) {
this.enhancementContext = enhancementContext; this.enhancementContext = enhancementContext;
} }
@ -66,4 +84,40 @@ class ByteBuddyEnhancementContext {
public boolean doBiDirectionalAssociationManagement(AnnotatedFieldDescription field) { public boolean doBiDirectionalAssociationManagement(AnnotatedFieldDescription field) {
return enhancementContext.doBiDirectionalAssociationManagement( field ); return enhancementContext.doBiDirectionalAssociationManagement( field );
} }
Optional<MethodDescription> resolveGetter(FieldDescription fieldDescription) {
Map<String, MethodDescription> getters = getterByTypeMap
.computeIfAbsent( fieldDescription.getDeclaringType().asErasure(), declaringType -> {
return MethodGraph.Compiler.DEFAULT.compile( declaringType )
.listNodes()
.asMethodList()
.filter( IS_GETTER )
.stream()
.collect( Collectors.toMap( MethodDescription::getActualName, Function.identity() ) );
} );
String capitalizedFieldName = Character.toUpperCase( fieldDescription.getName().charAt( 0 ) )
+ fieldDescription.getName().substring( 1 );
MethodDescription getCandidate = getters.get( "get" + capitalizedFieldName );
MethodDescription isCandidate = getters.get( "is" + capitalizedFieldName );
if ( getCandidate != null ) {
if ( isCandidate != null ) {
throw new MappingException(
String.format(
Locale.ROOT,
"In trying to locate getter for property [%s], Class [%s] defined " +
"both a `get` [%s] and `is` [%s] variant",
fieldDescription.getName(),
fieldDescription.getDeclaringType().getActualName(),
getCandidate.getActualName(),
isCandidate.getActualName() ) );
}
return Optional.of( getCandidate );
}
return Optional.ofNullable( isCandidate );
}
} }

View File

@ -15,12 +15,18 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.hibernate.MappingException;
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.spi.CollectionTracker; import org.hibernate.bytecode.enhance.spi.CollectionTracker;
@ -51,7 +57,6 @@ import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldDescription.InDefinedShape; import net.bytebuddy.description.field.FieldDescription.InDefinedShape;
import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.modifier.FieldPersistence; import net.bytebuddy.description.modifier.FieldPersistence;
import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDefinition;
@ -390,7 +395,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;
} }
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) { if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) {
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( annotatedField ); collectionList.add( annotatedField );
@ -420,7 +425,7 @@ public class EnhancerImpl implements Enhancer {
for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) { for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) {
if ( !Modifier.isStatic( ctField.getModifiers() ) ) { if ( !Modifier.isStatic( ctField.getModifiers() ) ) {
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) { if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) {
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( annotatedField ); collectionList.add( annotatedField );
@ -436,30 +441,18 @@ public class EnhancerImpl implements Enhancer {
return Character.toUpperCase( value.charAt( 0 ) ) + value.substring( 1 ); return Character.toUpperCase( value.charAt( 0 ) ) + value.substring( 1 );
} }
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() ) );
if ( methodList.size() == 1 ) {
return methodList.getOnly();
}
else {
return null;
}
}
static class AnnotatedFieldDescription implements UnloadedField { static class AnnotatedFieldDescription implements UnloadedField {
private final ByteBuddyEnhancementContext context;
private final FieldDescription fieldDescription; private final FieldDescription fieldDescription;
private AnnotationList annotations; private AnnotationList annotations;
AnnotatedFieldDescription(FieldDescription fieldDescription) { private Optional<MethodDescription> getter;
AnnotatedFieldDescription(ByteBuddyEnhancementContext context, FieldDescription fieldDescription) {
this.context = context;
this.fieldDescription = fieldDescription; this.fieldDescription = fieldDescription;
} }
@ -500,35 +493,43 @@ public class EnhancerImpl implements Enhancer {
return fieldDescription; return fieldDescription;
} }
Optional<MethodDescription> getGetter() {
if ( getter == null ) {
getter = context.resolveGetter( fieldDescription );
}
return getter;
}
private AnnotationList getAnnotations() { private AnnotationList getAnnotations() {
if ( annotations == null ) { if ( annotations == null ) {
annotations = doGetAnnotations( fieldDescription ); annotations = doGetAnnotations();
} }
return annotations; return annotations;
} }
private static AnnotationList doGetAnnotations(FieldDescription fieldDescription) { private AnnotationList doGetAnnotations() {
AnnotationDescription.Loadable<Access> access = fieldDescription.getDeclaringType().asErasure() AnnotationDescription.Loadable<Access> access = fieldDescription.getDeclaringType().asErasure()
.getDeclaredAnnotations().ofType( Access.class ); .getDeclaredAnnotations().ofType( Access.class );
if ( access != null && access.loadSilent().value() == AccessType.PROPERTY ) { if ( access != null && access.loadSilent().value() == AccessType.PROPERTY ) {
MethodDescription getter = getterOf( fieldDescription ); Optional<MethodDescription> getter = getGetter();
if ( getter == null ) { if ( getter.isPresent() ) {
return fieldDescription.getDeclaredAnnotations(); return getter.get().getDeclaredAnnotations();
} }
else { else {
return getter.getDeclaredAnnotations(); return fieldDescription.getDeclaredAnnotations();
} }
} }
else if ( access != null && access.loadSilent().value() == AccessType.FIELD ) { else if ( access != null && access.loadSilent().value() == AccessType.FIELD ) {
return fieldDescription.getDeclaredAnnotations(); return fieldDescription.getDeclaredAnnotations();
} }
else { else {
MethodDescription getter = getterOf( fieldDescription ); Optional<MethodDescription> getter = getGetter();
// Note that the order here is important // Note that the order here is important
List<AnnotationDescription> annotationDescriptions = new ArrayList<>(); List<AnnotationDescription> annotationDescriptions = new ArrayList<>();
if ( getter != null ) { if ( getter.isPresent() ) {
annotationDescriptions.addAll( getter.getDeclaredAnnotations() ); annotationDescriptions.addAll( getter.get().getDeclaredAnnotations() );
} }
annotationDescriptions.addAll( fieldDescription.getDeclaredAnnotations() ); annotationDescriptions.addAll( fieldDescription.getDeclaredAnnotations() );

View File

@ -129,7 +129,7 @@ final class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods.
); );
throw new EnhancementException( msg ); throw new EnhancementException( msg );
} }
return new AnnotatedFieldDescription( fields.getOnly() ); return new AnnotatedFieldDescription( enhancementContext, fields.getOnly() );
} }
@Override @Override

View File

@ -74,7 +74,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) { if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) {
continue; continue;
} }
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) { if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) {
persistentFieldList.add( annotatedField ); persistentFieldList.add( annotatedField );
} }
@ -110,7 +110,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) { if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) {
continue; continue;
} }
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField ); AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) { if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) {
persistentFieldList.add( annotatedField ); persistentFieldList.add( annotatedField );
} }