Skip to content

Commit

Permalink
Update Byte Buddy to v1.6.0. Use cache for type storage to avoid leaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphw authored and vladmihalcea committed Jan 12, 2017
1 parent 19469e8 commit 4a32f1a
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 78 deletions.
Expand Up @@ -8,12 +8,12 @@

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;
Expand Down Expand Up @@ -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,
Expand Down
Expand Up @@ -13,6 +13,8 @@
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;
Expand Down Expand Up @@ -116,7 +118,7 @@ private static Collection<FieldDescription> collectInheritPersistentFields(
@Override
public MethodVisitor wrap(
TypeDescription instrumentedType,
MethodDescription.InDefinedShape instrumentedMethod,
MethodDescription instrumentedMethod,
MethodVisitor methodVisitor,
Implementation.Context implementationContext,
TypePool typePool,
Expand Down
Expand Up @@ -13,6 +13,7 @@
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;
Expand Down Expand Up @@ -40,8 +41,8 @@

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() {
Expand All @@ -59,48 +60,41 @@ public ReflectionOptimizer getReflectionOptimizer(
findAccessors( clazz, getterNames, setterNames, types, getters, setters );
final Constructor<?> constructor = findConstructor( clazz );

Class fastClass = FAST_CLASSES.get( 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();
}

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 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);

fastClass = FAST_CLASSES.insert( clazz.getClassLoader(), clazz.getName(), fastClass );

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(
Expand Down
Expand Up @@ -13,9 +13,11 @@
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;
Expand Down Expand Up @@ -44,7 +46,8 @@
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;
Expand Down Expand Up @@ -86,38 +89,32 @@ private Class[] toArray(Set<Class> interfaces) {
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 ) );

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;
key.addAll( Arrays.<Class<?>>asList( interfaces ) );

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
Expand Down
2 changes: 1 addition & 1 deletion libraries.gradle
Expand Up @@ -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'
Expand Down

0 comments on commit 4a32f1a

Please sign in to comment.