Update Byte Buddy to v1.6.0. Use cache for type storage to avoid leaks.

This commit is contained in:
Rafael Winterhalter 2017-01-02 15:17:54 +01:00 committed by Vlad Mihalcea
parent 19469e8b4f
commit 4a32f1a0d5
5 changed files with 68 additions and 75 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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(

View File

@ -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

View File

@ -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'