Update Byte Buddy to v1.6.0. Use cache for type storage to avoid leaks.
This commit is contained in:
parent
19469e8b4f
commit
4a32f1a0d5
|
@ -8,12 +8,12 @@ package org.hibernate.bytecode.enhance.internal.bytebuddy;
|
|||
|
||||
import javax.persistence.Id;
|
||||
|
||||
import net.bytebuddy.description.method.MethodList;
|
||||
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.ClassFileVersion;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||
import net.bytebuddy.description.field.FieldDescription;
|
||||
import net.bytebuddy.description.field.FieldList;
|
||||
|
@ -47,7 +47,7 @@ class FieldAccessEnhancer implements AsmVisitorWrapper.ForDeclaredMethods.Method
|
|||
@Override
|
||||
public MethodVisitor wrap(
|
||||
TypeDescription instrumentedType,
|
||||
MethodDescription.InDefinedShape instrumentedMethod,
|
||||
MethodDescription instrumentedMethod,
|
||||
MethodVisitor methodVisitor,
|
||||
Implementation.Context implementationContext,
|
||||
TypePool typePool,
|
||||
|
|
|
@ -13,6 +13,8 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import javax.persistence.Embedded;
|
||||
|
||||
import net.bytebuddy.description.field.FieldList;
|
||||
import net.bytebuddy.description.method.MethodList;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
|
||||
import org.hibernate.engine.spi.CompositeOwner;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
|
@ -116,7 +118,7 @@ class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDeclaredMet
|
|||
@Override
|
||||
public MethodVisitor wrap(
|
||||
TypeDescription instrumentedType,
|
||||
MethodDescription.InDefinedShape instrumentedMethod,
|
||||
MethodDescription instrumentedMethod,
|
||||
MethodVisitor methodVisitor,
|
||||
Implementation.Context implementationContext,
|
||||
TypePool typePool,
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.concurrent.Callable;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import net.bytebuddy.TypeCache;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
|
@ -40,8 +41,8 @@ import net.bytebuddy.matcher.ElementMatchers;
|
|||
|
||||
public class BytecodeProviderImpl implements BytecodeProvider {
|
||||
|
||||
private final ConcurrentMap<Class, Class> FAST_CLASSES = new ConcurrentHashMap<Class, Class>();
|
||||
private final ConcurrentMap<Class, Class> BULK_ACCESSORS = new ConcurrentHashMap<Class, Class>();
|
||||
private final TypeCache<String> FAST_CLASSES = new TypeCache.WithInlineExpunction<String>(TypeCache.Sort.SOFT);
|
||||
private final TypeCache<String> BULK_ACCESSORS = new TypeCache.WithInlineExpunction<String>(TypeCache.Sort.SOFT);
|
||||
|
||||
@Override
|
||||
public ProxyFactoryFactory getProxyFactoryFactory() {
|
||||
|
@ -59,48 +60,41 @@ public class BytecodeProviderImpl implements BytecodeProvider {
|
|||
findAccessors( clazz, getterNames, setterNames, types, getters, setters );
|
||||
final Constructor<?> constructor = findConstructor( clazz );
|
||||
|
||||
Class fastClass = FAST_CLASSES.get( clazz );
|
||||
Class fastClass = FAST_CLASSES.findOrInsert( clazz.getClassLoader(), clazz.getName(), new Callable<Class<?>>() {
|
||||
@Override
|
||||
public Class<?> call() throws Exception {
|
||||
return new ByteBuddy()
|
||||
.with(TypeValidation.DISABLED)
|
||||
.with(new NamingStrategy.SuffixingRandom("HibernateInstantiator"))
|
||||
.subclass(ReflectionOptimizer.InstantiationOptimizer.class)
|
||||
.method(ElementMatchers.named("newInstance"))
|
||||
.intercept(MethodCall.construct(constructor))
|
||||
.make()
|
||||
.load(clazz.getClassLoader())
|
||||
.getLoaded();
|
||||
}
|
||||
}, clazz);
|
||||
|
||||
if ( fastClass == null ) {
|
||||
fastClass = new ByteBuddy()
|
||||
.with( TypeValidation.DISABLED )
|
||||
.with( new NamingStrategy.SuffixingRandom( "HibernateInstantiator" ) )
|
||||
.subclass( ReflectionOptimizer.InstantiationOptimizer.class )
|
||||
.method( ElementMatchers.named( "newInstance" ) )
|
||||
.intercept( MethodCall.construct( constructor ) )
|
||||
.make()
|
||||
.load( clazz.getClassLoader() )
|
||||
.getLoaded();
|
||||
}
|
||||
fastClass = FAST_CLASSES.insert( clazz.getClassLoader(), clazz.getName(), fastClass );
|
||||
|
||||
Class previousFastClass = FAST_CLASSES.putIfAbsent( clazz, fastClass );
|
||||
if ( previousFastClass != null ) {
|
||||
fastClass = previousFastClass;
|
||||
}
|
||||
|
||||
Class bulkAccessor = BULK_ACCESSORS.get( clazz );
|
||||
|
||||
if ( bulkAccessor == null ) {
|
||||
bulkAccessor = new ByteBuddy()
|
||||
.with( TypeValidation.DISABLED )
|
||||
.with( new NamingStrategy.SuffixingRandom( "HibernateAccessOptimizer" ) )
|
||||
.subclass( ReflectionOptimizer.AccessOptimizer.class )
|
||||
.method( ElementMatchers.named( "getPropertyValues" ) )
|
||||
.intercept( new Implementation.Simple( new GetPropertyValues( clazz, getters ) ) )
|
||||
.method( ElementMatchers.named( "setPropertyValues" ) )
|
||||
.intercept( new Implementation.Simple( new SetPropertyValues( clazz, setters ) ) )
|
||||
.method( ElementMatchers.named( "getPropertyNames" ) )
|
||||
.intercept( MethodCall.call( new CloningPropertyCall( getterNames ) ) )
|
||||
.make()
|
||||
.load( clazz.getClassLoader() )
|
||||
.getLoaded();
|
||||
}
|
||||
|
||||
|
||||
Class previousBulkAccessor = BULK_ACCESSORS.putIfAbsent( clazz, fastClass );
|
||||
if ( previousBulkAccessor != null ) {
|
||||
bulkAccessor = previousBulkAccessor;
|
||||
}
|
||||
Class bulkAccessor = BULK_ACCESSORS.findOrInsert( clazz.getClassLoader(), clazz.getName(), new Callable<Class<?>>() {
|
||||
@Override
|
||||
public Class<?> call() throws Exception {
|
||||
return new ByteBuddy()
|
||||
.with(TypeValidation.DISABLED)
|
||||
.with(new NamingStrategy.SuffixingRandom("HibernateAccessOptimizer"))
|
||||
.subclass(ReflectionOptimizer.AccessOptimizer.class)
|
||||
.method(ElementMatchers.named("getPropertyValues"))
|
||||
.intercept(new Implementation.Simple(new GetPropertyValues(clazz, getters)))
|
||||
.method(ElementMatchers.named("setPropertyValues"))
|
||||
.intercept(new Implementation.Simple(new SetPropertyValues(clazz, setters)))
|
||||
.method(ElementMatchers.named("getPropertyNames"))
|
||||
.intercept(MethodCall.call(new CloningPropertyCall(getterNames)))
|
||||
.make()
|
||||
.load(clazz.getClassLoader())
|
||||
.getLoaded();
|
||||
}
|
||||
}, clazz);
|
||||
|
||||
try {
|
||||
return new ReflectionOptimizerImpl(
|
||||
|
|
|
@ -13,9 +13,11 @@ import java.util.Arrays;
|
|||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import net.bytebuddy.TypeCache;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
@ -44,7 +46,8 @@ import static org.hibernate.internal.CoreLogging.messageLogger;
|
|||
public class ByteBuddyProxyFactory implements ProxyFactory, Serializable {
|
||||
private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyFactory.class );
|
||||
|
||||
private static final ConcurrentMap<Set<Class>, Class> CACHE = new ConcurrentHashMap<Set<Class>, Class>();
|
||||
private static final TypeCache<TypeCache.SimpleKey> CACHE =
|
||||
new TypeCache.WithInlineExpunction<TypeCache.SimpleKey>(TypeCache.Sort.SOFT);
|
||||
|
||||
private Class persistentClass;
|
||||
private String entityName;
|
||||
|
@ -86,38 +89,32 @@ public class ByteBuddyProxyFactory implements ProxyFactory, Serializable {
|
|||
public static Class buildProxy(
|
||||
final Class persistentClass,
|
||||
final Class[] interfaces) {
|
||||
Set<Class> key = new HashSet<Class>();
|
||||
Set<Class<?>> key = new HashSet<Class<?>>();
|
||||
if ( interfaces.length == 1 ) {
|
||||
key.add( persistentClass );
|
||||
}
|
||||
key.addAll( Arrays.asList( interfaces ) );
|
||||
key.addAll( Arrays.<Class<?>>asList( interfaces ) );
|
||||
|
||||
Class<?> proxy = CACHE.get( key );
|
||||
if ( proxy != null ) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
proxy = new ByteBuddy()
|
||||
.with( TypeValidation.DISABLED )
|
||||
.with( new NamingStrategy.SuffixingRandom( "HibernateProxy" ) )
|
||||
.subclass( interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING )
|
||||
.implement( (Type[]) interfaces )
|
||||
.method( ElementMatchers.isVirtual().and( ElementMatchers.not( ElementMatchers.isFinalizer() ) ) )
|
||||
.intercept( MethodDelegation.to( ProxyConfiguration.InterceptorDispatcher.class ) )
|
||||
.method( ElementMatchers.nameStartsWith( "$$_hibernate_" ).and( ElementMatchers.isVirtual() ) )
|
||||
.intercept( SuperMethodCall.INSTANCE )
|
||||
.defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE )
|
||||
.implement( ProxyConfiguration.class )
|
||||
.intercept( FieldAccessor.ofField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME ).withAssigner( Assigner.DEFAULT, Assigner.Typing.DYNAMIC ) )
|
||||
.make()
|
||||
.load( persistentClass.getClassLoader() )
|
||||
.getLoaded();
|
||||
|
||||
Class previousProxy = CACHE.putIfAbsent( key, proxy );
|
||||
if ( previousProxy != null ) {
|
||||
proxy = previousProxy;
|
||||
}
|
||||
return proxy;
|
||||
return CACHE.findOrInsert(persistentClass.getClassLoader(), new TypeCache.SimpleKey(key), new Callable<Class<?>>() {
|
||||
@Override
|
||||
public Class<?> call() throws Exception {
|
||||
return new ByteBuddy()
|
||||
.with(TypeValidation.DISABLED)
|
||||
.with(new NamingStrategy.SuffixingRandom("HibernateProxy"))
|
||||
.subclass(interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
|
||||
.implement((Type[]) interfaces)
|
||||
.method(ElementMatchers.isVirtual().and(ElementMatchers.not(ElementMatchers.isFinalizer())))
|
||||
.intercept(MethodDelegation.to(ProxyConfiguration.InterceptorDispatcher.class))
|
||||
.method(ElementMatchers.nameStartsWith("$$_hibernate_").and(ElementMatchers.isVirtual()))
|
||||
.intercept(SuperMethodCall.INSTANCE)
|
||||
.defineField(ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE)
|
||||
.implement(ProxyConfiguration.class)
|
||||
.intercept(FieldAccessor.ofField(ProxyConfiguration.INTERCEPTOR_FIELD_NAME).withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC))
|
||||
.make()
|
||||
.load(persistentClass.getClassLoader())
|
||||
.getLoaded();
|
||||
}
|
||||
}, persistentClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,7 @@ ext {
|
|||
cdiVersion = '1.1'
|
||||
|
||||
javassistVersion = '3.20.0-GA'
|
||||
byteBuddyVersion = '1.5.4'
|
||||
byteBuddyVersion = '1.6.0'
|
||||
|
||||
// Wildfly version targeted by module ZIP; Arquillian/Shrinkwrap versions used for CDI testing and testing the module ZIP
|
||||
wildflyVersion = '10.1.0.Final'
|
||||
|
|
Loading…
Reference in New Issue