mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-07 11:48:18 +00:00
HHH-7686 Allow lazy loading outside of a transaction after dynamic map proxy deserialization if the proper settings were enabled
In theory, trying to deserialize MapLazyInitializer instances that were serialized before this patch should still work, although using such instances (i.e. trying to access any method on the proxy) would still fail, just like it used to before this patch.
This commit is contained in:
parent
1522efc0ad
commit
f3e62ea795
@ -45,8 +45,17 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||
private boolean allowLoadOutsideTransaction;
|
||||
|
||||
/**
|
||||
* For serialization from the non-pojo initializers (HHH-3309)
|
||||
* @deprecated This constructor was initially intended for serialization only, and is not useful anymore.
|
||||
* In any case it should not be relied on by user code.
|
||||
* Subclasses should rather implement Serializable with an {@code Object writeReplace()} method returning
|
||||
* a subclass of {@link AbstractSerializableProxy},
|
||||
* which in turn implements Serializable and an {@code Object readResolve()} method
|
||||
* instantiating the {@link AbstractLazyInitializer} subclass
|
||||
* and calling {@link AbstractSerializableProxy#afterDeserialization(AbstractLazyInitializer)} on it.
|
||||
* See {@link org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor} and
|
||||
* {@link org.hibernate.proxy.pojo.bytebuddy.SerializableProxy} for examples.
|
||||
*/
|
||||
@Deprecated
|
||||
protected AbstractLazyInitializer() {
|
||||
}
|
||||
|
||||
@ -240,7 +249,7 @@ else if ( session.isOpen() && session.isConnected() ) {
|
||||
* and the entity being proxied has been loaded and added to the persistence context
|
||||
* of that session since the proxy was created.
|
||||
*/
|
||||
protected final void initializeWithoutLoadIfPossible() {
|
||||
public final void initializeWithoutLoadIfPossible() {
|
||||
if ( !initialized && session != null && session.isOpen() ) {
|
||||
final EntityKey key = session.generateEntityKey(
|
||||
getIdentifier(),
|
||||
@ -380,7 +389,7 @@ public final void setReadOnly(boolean readOnly) {
|
||||
*
|
||||
* @throws IllegalStateException if isReadOnlySettingAvailable() == true
|
||||
*/
|
||||
protected final Boolean isReadOnlyBeforeAttachedToSession() {
|
||||
public final Boolean isReadOnlyBeforeAttachedToSession() {
|
||||
if ( isReadOnlySettingAvailable() ) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot call isReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true [" + entityName + "#" + id + "]"
|
||||
|
@ -9,7 +9,7 @@
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Convenience base class for SerializableProxy.
|
||||
* Convenience base class for the serialized form of {@link AbstractLazyInitializer}.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
|
@ -31,4 +31,20 @@ public Class getPersistentClass() {
|
||||
throw new UnsupportedOperationException("dynamic-map entity representation");
|
||||
}
|
||||
|
||||
// Expose the following methods to MapProxy by overriding them (so that classes in this package see them)
|
||||
|
||||
@Override
|
||||
protected void prepareForPossibleLoadingOutsideTransaction() {
|
||||
super.prepareForPossibleLoadingOutsideTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAllowLoadOutsideTransaction() {
|
||||
return super.isAllowLoadOutsideTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSessionFactoryUuid() {
|
||||
return super.getSessionFactoryUuid();
|
||||
}
|
||||
}
|
||||
|
@ -22,14 +22,12 @@ public class MapProxy implements HibernateProxy, Map, Serializable {
|
||||
|
||||
private MapLazyInitializer li;
|
||||
|
||||
private Object replacement;
|
||||
|
||||
MapProxy(MapLazyInitializer li) {
|
||||
this.li = li;
|
||||
}
|
||||
|
||||
public Object writeReplace() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LazyInitializer getHibernateLazyInitializer() {
|
||||
return li;
|
||||
}
|
||||
@ -82,4 +80,34 @@ public Object put(Object key, Object value) {
|
||||
return li.getMap().put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object writeReplace() {
|
||||
/*
|
||||
* If the target has already been loaded somewhere, just not set on the proxy,
|
||||
* then use it to initialize the proxy so that we will serialize that instead of the proxy.
|
||||
*/
|
||||
li.initializeWithoutLoadIfPossible();
|
||||
|
||||
if ( li.isUninitialized() ) {
|
||||
if ( replacement == null ) {
|
||||
li.prepareForPossibleLoadingOutsideTransaction();
|
||||
replacement = serializableProxy();
|
||||
}
|
||||
return replacement;
|
||||
}
|
||||
else {
|
||||
return li.getImplementation();
|
||||
}
|
||||
}
|
||||
|
||||
private Object serializableProxy() {
|
||||
return new SerializableMapProxy(
|
||||
li.getEntityName(),
|
||||
li.getIdentifier(),
|
||||
( li.isReadOnlySettingAvailable() ? Boolean.valueOf( li.isReadOnly() ) : li.isReadOnlyBeforeAttachedToSession() ),
|
||||
li.getSessionFactoryUuid(),
|
||||
li.isAllowLoadOutsideTransaction()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.proxy.map;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.proxy.AbstractSerializableProxy;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor;
|
||||
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
public final class SerializableMapProxy extends AbstractSerializableProxy {
|
||||
|
||||
public SerializableMapProxy(
|
||||
String entityName,
|
||||
Serializable id,
|
||||
Boolean readOnly,
|
||||
String sessionFactoryUuid,
|
||||
boolean allowLoadOutsideTransaction) {
|
||||
super( entityName, id, readOnly, sessionFactoryUuid, allowLoadOutsideTransaction );
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
MapLazyInitializer initializer = new MapLazyInitializer( getEntityName(), getId(), null );
|
||||
afterDeserialization( initializer );
|
||||
return new MapProxy( initializer );
|
||||
}
|
||||
}
|
@ -21,7 +21,6 @@
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.map.MapProxy;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
@ -86,7 +85,6 @@ public void prepare() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-7686")
|
||||
@FailureExpected(jiraKey = "HHH-7686")
|
||||
public void testInitializedProxySerializationIfTargetInPersistenceContext() {
|
||||
final Session s = openSession();
|
||||
|
||||
@ -128,7 +126,6 @@ public void testInitializedProxySerializationIfTargetInPersistenceContext() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-7686")
|
||||
@FailureExpected(jiraKey = "HHH-7686")
|
||||
public void testUninitializedProxySerializationIfTargetInPersistenceContext() {
|
||||
final Session s = openSession();
|
||||
|
||||
@ -210,7 +207,6 @@ public void testProxyInitializationWithoutTX() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-7686")
|
||||
@FailureExpected(jiraKey = "HHH-7686")
|
||||
public void testProxyInitializationWithoutTXAfterDeserialization() {
|
||||
final Session s = openSession();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user