From 0452d7682943e3b141180fd9ab5db63499e4c203 Mon Sep 17 00:00:00 2001 From: Henry Clout Date: Mon, 30 Mar 2020 23:00:05 +0100 Subject: [PATCH] HHH-13915 : Prevent state sharing in basic proxies. Basic proxies were being created with a shared interceptor. As the interceptor is stateful, this lead to cross-thread data leakage and thus intermittently broken persistence. This mod creates an interceptor per proxy, preventing leaking of state. --- .../internal/bytebuddy/BasicProxyFactoryImpl.java | 7 ++++--- .../bytebuddy/ByteBuddyBasicProxyFactoryTest.java | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java index 4aea83519dc5..7e59797d99c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java @@ -24,7 +24,6 @@ public class BasicProxyFactoryImpl implements BasicProxyFactory { private static final String PROXY_NAMING_SUFFIX = "HibernateBasicProxy"; private final Class proxyClass; - private final ProxyConfiguration.Interceptor interceptor; private final Constructor proxyClassConstructor; @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -54,7 +53,7 @@ public BasicProxyFactoryImpl(final Class superClass, final Class interfaceClass, .intercept( byteBuddyState.getProxyDefinitionHelpers().getInterceptorFieldAccessor() ) ) ); - this.interceptor = new PassThroughInterceptor( proxyClass.getName() ); + try { proxyClassConstructor = proxyClass.getConstructor(); } @@ -76,7 +75,9 @@ public Object getProxy() { if ( proxyConfiguration == null ) { throw new HibernateException( "Produced proxy does not correctly implement ProxyConfiguration" ); } - proxyConfiguration.$$_hibernate_set_interceptor( this.interceptor ); + // Create a dedicated interceptor for the proxy. This is required as the interceptor is stateful. + final ProxyConfiguration.Interceptor interceptor = new PassThroughInterceptor( proxyClass.getName() ); + proxyConfiguration.$$_hibernate_set_interceptor( interceptor ); return instance; } diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java index 3ba93058b2ed..cc358be61f66 100644 --- a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java @@ -13,12 +13,12 @@ import org.hibernate.testing.orm.junit.JiraKey; import org.junit.Test; -@JiraKey(value = "HHH-12786") public class ByteBuddyBasicProxyFactoryTest { private static final BasicProxyFactoryImpl BASIC_PROXY_FACTORY = new BasicProxyFactoryImpl( Entity.class, null, new ByteBuddyState() ); @Test + @JiraKey(value = "HHH-12786") public void testEqualsHashCode() { Object entityProxy = BASIC_PROXY_FACTORY.getProxy(); @@ -30,6 +30,7 @@ public void testEqualsHashCode() { } @Test + @JiraKey(value = "HHH-12786") public void testToString() { Object entityProxy = BASIC_PROXY_FACTORY.getProxy(); @@ -37,6 +38,7 @@ public void testToString() { } @Test + @JiraKey(value = "HHH-12786") public void testGetterSetter() { Entity entityProxy = (Entity) BASIC_PROXY_FACTORY.getProxy(); @@ -50,12 +52,23 @@ public void testGetterSetter() { } @Test + @JiraKey(value = "HHH-12786") public void testNonGetterSetterMethod() { Entity entityProxy = (Entity) BASIC_PROXY_FACTORY.getProxy(); assertNull( entityProxy.otherMethod() ); } + @Test + @JiraKey(value = "HHH-13915") + public void testProxiesDoNotShareState() { + Entity entityAProxy = (Entity) BASIC_PROXY_FACTORY.getProxy(); + entityAProxy.setString( "John Irving" ); + + Entity entityBProxy = (Entity) BASIC_PROXY_FACTORY.getProxy(); + assertNull( entityBProxy.getString() ); + } + public static class Entity { private String string;