HHH-13097 Cache the resolution of the getters
This commit is contained in:
parent
43ee75b966
commit
38e48ef0bc
|
@ -9,6 +9,7 @@ package org.hibernate.bytecode.enhance.internal.bytebuddy;
|
|||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
|
@ -166,12 +167,12 @@ final class BiDirectionalAssociationHandler implements Implementation {
|
|||
return persistentField.getType();
|
||||
}
|
||||
else {
|
||||
MethodDescription getter = EnhancerImpl.getterOf( persistentField );
|
||||
if ( getter == null ) {
|
||||
return persistentField.getType();
|
||||
Optional<MethodDescription> getter = persistentField.getGetter();
|
||||
if ( getter.isPresent() ) {
|
||||
return getter.get().getReturnType();
|
||||
}
|
||||
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) {
|
||||
for ( FieldDescription f : targetEntity.getDeclaredFields() ) {
|
||||
AnnotatedFieldDescription annotatedF = new AnnotatedFieldDescription( f );
|
||||
AnnotatedFieldDescription annotatedF = new AnnotatedFieldDescription( context, f );
|
||||
if ( context.isPersistentField( annotatedF )
|
||||
&& target.getName().equals( getMappedByNotManyToMany( annotatedF ) )
|
||||
&& target.getDeclaringType().asErasure().isAssignableTo( entityType( annotatedF.getType() ) ) ) {
|
||||
|
|
|
@ -6,15 +6,33 @@
|
|||
*/
|
||||
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.spi.EnhancementContext;
|
||||
|
||||
import net.bytebuddy.description.field.FieldDescription;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.scaffold.MethodGraph;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
class ByteBuddyEnhancementContext {
|
||||
|
||||
private static final ElementMatcher.Junction<MethodDescription> IS_GETTER = isGetter();
|
||||
|
||||
private final EnhancementContext enhancementContext;
|
||||
|
||||
private final ConcurrentHashMap<TypeDescription, Map<String, MethodDescription>> getterByTypeMap = new ConcurrentHashMap<>();
|
||||
|
||||
ByteBuddyEnhancementContext(EnhancementContext enhancementContext) {
|
||||
this.enhancementContext = enhancementContext;
|
||||
}
|
||||
|
@ -66,4 +84,40 @@ class ByteBuddyEnhancementContext {
|
|||
public boolean doBiDirectionalAssociationManagement(AnnotatedFieldDescription 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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,18 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
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 javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
|
||||
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
|
||||
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.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;
|
||||
|
@ -390,7 +395,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) {
|
||||
continue;
|
||||
}
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField );
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
|
||||
if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) {
|
||||
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
|
||||
collectionList.add( annotatedField );
|
||||
|
@ -420,7 +425,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
|
||||
for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) {
|
||||
if ( !Modifier.isStatic( ctField.getModifiers() ) ) {
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField );
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
|
||||
if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) {
|
||||
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
|
||||
collectionList.add( annotatedField );
|
||||
|
@ -436,30 +441,18 @@ public class EnhancerImpl implements Enhancer {
|
|||
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 {
|
||||
|
||||
private final ByteBuddyEnhancementContext context;
|
||||
|
||||
private final FieldDescription fieldDescription;
|
||||
|
||||
private AnnotationList annotations;
|
||||
|
||||
AnnotatedFieldDescription(FieldDescription fieldDescription) {
|
||||
private Optional<MethodDescription> getter;
|
||||
|
||||
AnnotatedFieldDescription(ByteBuddyEnhancementContext context, FieldDescription fieldDescription) {
|
||||
this.context = context;
|
||||
this.fieldDescription = fieldDescription;
|
||||
}
|
||||
|
||||
|
@ -500,35 +493,43 @@ public class EnhancerImpl implements Enhancer {
|
|||
return fieldDescription;
|
||||
}
|
||||
|
||||
Optional<MethodDescription> getGetter() {
|
||||
if ( getter == null ) {
|
||||
getter = context.resolveGetter( fieldDescription );
|
||||
}
|
||||
|
||||
return getter;
|
||||
}
|
||||
|
||||
private AnnotationList getAnnotations() {
|
||||
if ( annotations == null ) {
|
||||
annotations = doGetAnnotations( fieldDescription );
|
||||
annotations = doGetAnnotations();
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
private static AnnotationList doGetAnnotations(FieldDescription fieldDescription) {
|
||||
private AnnotationList doGetAnnotations() {
|
||||
AnnotationDescription.Loadable<Access> 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();
|
||||
Optional<MethodDescription> getter = getGetter();
|
||||
if ( getter.isPresent() ) {
|
||||
return getter.get().getDeclaredAnnotations();
|
||||
}
|
||||
else {
|
||||
return getter.getDeclaredAnnotations();
|
||||
return fieldDescription.getDeclaredAnnotations();
|
||||
}
|
||||
}
|
||||
else if ( access != null && access.loadSilent().value() == AccessType.FIELD ) {
|
||||
return fieldDescription.getDeclaredAnnotations();
|
||||
}
|
||||
else {
|
||||
MethodDescription getter = getterOf( fieldDescription );
|
||||
Optional<MethodDescription> getter = getGetter();
|
||||
|
||||
// Note that the order here is important
|
||||
List<AnnotationDescription> annotationDescriptions = new ArrayList<>();
|
||||
if ( getter != null ) {
|
||||
annotationDescriptions.addAll( getter.getDeclaredAnnotations() );
|
||||
if ( getter.isPresent() ) {
|
||||
annotationDescriptions.addAll( getter.get().getDeclaredAnnotations() );
|
||||
}
|
||||
annotationDescriptions.addAll( fieldDescription.getDeclaredAnnotations() );
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ final class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods.
|
|||
);
|
||||
throw new EnhancementException( msg );
|
||||
}
|
||||
return new AnnotatedFieldDescription( fields.getOnly() );
|
||||
return new AnnotatedFieldDescription( enhancementContext, fields.getOnly() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -74,7 +74,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
|
|||
if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) {
|
||||
continue;
|
||||
}
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField );
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
|
||||
if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) {
|
||||
persistentFieldList.add( annotatedField );
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
|
|||
if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) {
|
||||
continue;
|
||||
}
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( ctField );
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
|
||||
if ( !ctField.isStatic() && enhancementContext.isPersistentField( annotatedField ) ) {
|
||||
persistentFieldList.add( annotatedField );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue