HHH-15090 Fix access to public field with extended bytecode enhancement returning null for entity lazy-loaded from polymorphic toOne association

This commit is contained in:
Yoann Rodière 2022-02-24 17:44:21 +01:00
parent 2ea04dc524
commit 223856cfd0
2 changed files with 17 additions and 11 deletions

View File

@ -24,6 +24,7 @@ import java.security.PrivilegedAction;
import java.util.function.Function; import java.util.function.Function;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
import org.hibernate.bytecode.spi.BasicProxyFactory; import org.hibernate.bytecode.spi.BasicProxyFactory;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.proxy.ProxyConfiguration; import org.hibernate.proxy.ProxyConfiguration;
@ -248,7 +249,7 @@ public final class ByteBuddyState {
private final ElementMatcher<? super MethodDescription> groovyGetMetaClassFilter; private final ElementMatcher<? super MethodDescription> groovyGetMetaClassFilter;
private final ElementMatcher<? super MethodDescription> virtualNotFinalizerFilter; private final ElementMatcher<? super MethodDescription> virtualNotFinalizerFilter;
private final ElementMatcher<? super MethodDescription> hibernateGeneratedMethodFilter; private final ElementMatcher<? super MethodDescription> proxyNonInterceptedMethodFilter;
private final MethodDelegation delegateToInterceptorDispatcherMethodDelegation; private final MethodDelegation delegateToInterceptorDispatcherMethodDelegation;
private final FieldAccessor.PropertyConfigurable interceptorFieldAccessor; private final FieldAccessor.PropertyConfigurable interceptorFieldAccessor;
@ -256,7 +257,11 @@ public final class ByteBuddyState {
this.groovyGetMetaClassFilter = isSynthetic().and( named( "getMetaClass" ) this.groovyGetMetaClassFilter = isSynthetic().and( named( "getMetaClass" )
.and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) ); .and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) );
this.virtualNotFinalizerFilter = isVirtual().and( not( isFinalizer() ) ); this.virtualNotFinalizerFilter = isVirtual().and( not( isFinalizer() ) );
this.hibernateGeneratedMethodFilter = nameStartsWith( "$$_hibernate_" ).and( isVirtual() ); this.proxyNonInterceptedMethodFilter = nameStartsWith( "$$_hibernate_" ).and( isVirtual() )
// HHH-15090: Don't apply extended enhancement reader/writer methods to the proxy;
// those need to be executed on the actual entity.
.and( not( nameStartsWith( EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX ) ) )
.and( not( nameStartsWith( EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX ) ) );
PrivilegedAction<MethodDelegation> delegateToInterceptorDispatcherMethodDelegationPrivilegedAction = PrivilegedAction<MethodDelegation> delegateToInterceptorDispatcherMethodDelegationPrivilegedAction =
new PrivilegedAction<MethodDelegation>() { new PrivilegedAction<MethodDelegation>() {
@ -294,8 +299,8 @@ public final class ByteBuddyState {
return virtualNotFinalizerFilter; return virtualNotFinalizerFilter;
} }
public ElementMatcher<? super MethodDescription> getHibernateGeneratedMethodFilter() { public ElementMatcher<? super MethodDescription> getProxyNonInterceptedMethodFilter() {
return hibernateGeneratedMethodFilter; return proxyNonInterceptedMethodFilter;
} }
public MethodDelegation getDelegateToInterceptorDispatcherMethodDelegation() { public MethodDelegation getDelegateToInterceptorDispatcherMethodDelegation() {

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.proxy.pojo.bytebuddy; package org.hibernate.proxy.pojo.bytebuddy;
import static org.hibernate.internal.CoreLogging.messageLogger;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -31,8 +33,6 @@ import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.SuperMethodCall; import net.bytebuddy.implementation.SuperMethodCall;
import static org.hibernate.internal.CoreLogging.messageLogger;
public class ByteBuddyProxyHelper implements Serializable { public class ByteBuddyProxyHelper implements Serializable {
private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyHelper.class ); private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyHelper.class );
@ -64,18 +64,19 @@ public class ByteBuddyProxyHelper implements Serializable {
} }
private Function<ByteBuddy, DynamicType.Builder<?>> proxyBuilder(Class persistentClass, Class[] interfaces) { private Function<ByteBuddy, DynamicType.Builder<?>> proxyBuilder(Class persistentClass, Class[] interfaces) {
ByteBuddyState.ProxyDefinitionHelpers helpers = byteBuddyState.getProxyDefinitionHelpers();
return byteBuddy -> byteBuddy return byteBuddy -> byteBuddy
.ignore( byteBuddyState.getProxyDefinitionHelpers().getGroovyGetMetaClassFilter() ) .ignore( helpers.getGroovyGetMetaClassFilter() )
.with( new NamingStrategy.SuffixingRandom( PROXY_NAMING_SUFFIX, new NamingStrategy.SuffixingRandom.BaseNameResolver.ForFixedValue( persistentClass.getName() ) ) ) .with( new NamingStrategy.SuffixingRandom( PROXY_NAMING_SUFFIX, new NamingStrategy.SuffixingRandom.BaseNameResolver.ForFixedValue( persistentClass.getName() ) ) )
.subclass( interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING ) .subclass( interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING )
.implement( (Type[]) interfaces ) .implement( (Type[]) interfaces )
.method( byteBuddyState.getProxyDefinitionHelpers().getVirtualNotFinalizerFilter() ) .method( helpers.getVirtualNotFinalizerFilter() )
.intercept( byteBuddyState.getProxyDefinitionHelpers().getDelegateToInterceptorDispatcherMethodDelegation() ) .intercept( helpers.getDelegateToInterceptorDispatcherMethodDelegation() )
.method( byteBuddyState.getProxyDefinitionHelpers().getHibernateGeneratedMethodFilter() ) .method( helpers.getProxyNonInterceptedMethodFilter() )
.intercept( SuperMethodCall.INSTANCE ) .intercept( SuperMethodCall.INSTANCE )
.defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE ) .defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE )
.implement( ProxyConfiguration.class ) .implement( ProxyConfiguration.class )
.intercept( byteBuddyState.getProxyDefinitionHelpers().getInterceptorFieldAccessor() ); .intercept( helpers.getInterceptorFieldAccessor() );
} }
public HibernateProxy deserializeProxy(SerializableProxy serializableProxy) { public HibernateProxy deserializeProxy(SerializableProxy serializableProxy) {