HHH-3870 - Hibernate proxies Groovy's getMetaClass method breaking proxies when used with Groovy
This commit is contained in:
parent
6379a42a58
commit
af080884d1
|
@ -14,34 +14,31 @@ 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;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.ProxyFactory;
|
||||
import org.hibernate.proxy.ProxyConfiguration;
|
||||
import org.hibernate.proxy.ProxyFactory;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.NamingStrategy;
|
||||
import net.bytebuddy.TypeCache;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.scaffold.TypeValidation;
|
||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.SuperMethodCall;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
public class ByteBuddyProxyFactory implements ProxyFactory, Serializable {
|
||||
private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyFactory.class );
|
||||
|
@ -95,26 +92,23 @@ public class ByteBuddyProxyFactory implements ProxyFactory, Serializable {
|
|||
}
|
||||
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();
|
||||
}
|
||||
}, CACHE);
|
||||
return CACHE.findOrInsert( persistentClass.getClassLoader(), new TypeCache.SimpleKey(key), () ->
|
||||
new ByteBuddy()
|
||||
.ignore( isSynthetic().and( named( "getMetaClass" ).and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) ) )
|
||||
.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(isVirtual().and(not(isFinalizer())))
|
||||
.intercept(MethodDelegation.to(ProxyConfiguration.InterceptorDispatcher.class))
|
||||
.method(nameStartsWith("$$_hibernate_").and(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(), CACHE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,11 +33,14 @@ import static org.hibernate.internal.CoreLogging.messageLogger;
|
|||
public class JavassistProxyFactory implements ProxyFactory, Serializable {
|
||||
private static final CoreMessageLogger LOG = messageLogger( JavassistProxyFactory.class );
|
||||
|
||||
private static final MethodFilter FINALIZE_FILTER = new MethodFilter() {
|
||||
public boolean isHandled(Method m) {
|
||||
// skip finalize methods
|
||||
return !( m.getParameterCount() == 0 && m.getName().equals( "finalize" ) );
|
||||
}
|
||||
private static final MethodFilter EXCLUDE_FILTER = m -> {
|
||||
// skip finalize methods and Groovy getMetaClass
|
||||
return !(
|
||||
m.getParameterCount() == 0 && m.getName().equals( "finalize" ) || (
|
||||
m.getName().equals( "getMetaClass" ) &&
|
||||
m.getReturnType().getName().equals( "groovy.lang.MetaClass" )
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
private Class persistentClass;
|
||||
|
@ -98,7 +101,7 @@ public class JavassistProxyFactory implements ProxyFactory, Serializable {
|
|||
};
|
||||
factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
|
||||
factory.setInterfaces( interfaces );
|
||||
factory.setFilter( FINALIZE_FILTER );
|
||||
factory.setFilter( EXCLUDE_FILTER );
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue