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.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() ) ) ) {
|
||||||
|
|
|
@ -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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue