HHH-7686 Clarify and test initialization code in the writeReplace() method in proxies
If we copy the behavior of "traditional" (non-map) proxies to the "dynamic-map" proxies, we'd better know what this behavior is and be sure it works correctly.
This commit is contained in:
parent
e0900b17e2
commit
f2b4aedc03
|
@ -233,6 +233,26 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to initialize the proxy without loading anything from the database.
|
||||||
|
*
|
||||||
|
* This will only have any effect if the proxy is still attached to a session,
|
||||||
|
* 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() {
|
||||||
|
if ( !initialized && session != null && session.isOpen() ) {
|
||||||
|
final EntityKey key = session.generateEntityKey(
|
||||||
|
getIdentifier(),
|
||||||
|
session.getFactory().getMetamodel().entityPersister( getEntityName() )
|
||||||
|
);
|
||||||
|
final Object entity = session.getPersistenceContext().getEntity( key );
|
||||||
|
if ( entity != null ) {
|
||||||
|
setImplementation( entity );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize internal state based on the currently attached session,
|
* Initialize internal state based on the currently attached session,
|
||||||
* in order to be ready to load data even after the proxy is detached from the session.
|
* in order to be ready to load data even after the proxy is detached from the session.
|
||||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.proxy.pojo;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.MarkerObject;
|
import org.hibernate.internal.util.MarkerObject;
|
||||||
import org.hibernate.proxy.AbstractLazyInitializer;
|
import org.hibernate.proxy.AbstractLazyInitializer;
|
||||||
|
@ -91,17 +90,11 @@ public abstract class BasicLazyInitializer extends AbstractLazyInitializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object getReplacement() {
|
private Object getReplacement() {
|
||||||
final SharedSessionContractImplementor session = getSession();
|
/*
|
||||||
if ( isUninitialized() && session != null && session.isOpen() ) {
|
* If the target has already been loaded somewhere, just not set on the proxy,
|
||||||
final EntityKey key = session.generateEntityKey(
|
* then use it to initialize the proxy so that we will serialize that instead of the proxy.
|
||||||
getIdentifier(),
|
*/
|
||||||
session.getFactory().getMetamodel().entityPersister( getEntityName() )
|
initializeWithoutLoadIfPossible();
|
||||||
);
|
|
||||||
final Object entity = session.getPersistenceContext().getEntity( key );
|
|
||||||
if ( entity != null ) {
|
|
||||||
setImplementation( entity );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isUninitialized() ) {
|
if ( isUninitialized() ) {
|
||||||
if ( replacement == null ) {
|
if ( replacement == null ) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.serialization;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -94,6 +95,86 @@ public class EntityProxySerializationTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that serializing an initialized proxy will serialize the target instead.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
public void testInitializedProxySerializationIfTargetInPersistenceContext() {
|
||||||
|
final Session s = openSession();
|
||||||
|
|
||||||
|
final Transaction t = s.beginTransaction();
|
||||||
|
try {
|
||||||
|
final ChildEntity child = s.find( ChildEntity.class, 1L );
|
||||||
|
|
||||||
|
final SimpleEntity parent = child.getParent();
|
||||||
|
|
||||||
|
// assert we have an uninitialized proxy
|
||||||
|
assertTrue( parent instanceof HibernateProxy );
|
||||||
|
assertFalse( Hibernate.isInitialized( parent ) );
|
||||||
|
|
||||||
|
// Initialize the proxy
|
||||||
|
parent.getName();
|
||||||
|
assertTrue( Hibernate.isInitialized( parent ) );
|
||||||
|
|
||||||
|
// serialize/deserialize the proxy
|
||||||
|
final SimpleEntity deserializedParent = (SimpleEntity) SerializationHelper.clone( parent );
|
||||||
|
|
||||||
|
// assert the deserialized object is no longer a proxy, but the target of the proxy
|
||||||
|
assertFalse( deserializedParent instanceof HibernateProxy );
|
||||||
|
assertEquals( "TheParent", deserializedParent.getName() );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( t.isActive() ) {
|
||||||
|
t.rollback();
|
||||||
|
}
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that serializing a proxy which is not initialized
|
||||||
|
* but whose target has been (separately) added to the persistence context
|
||||||
|
* will serialize the target instead.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
public void testUninitializedProxySerializationIfTargetInPersistenceContext() {
|
||||||
|
final Session s = openSession();
|
||||||
|
|
||||||
|
final Transaction t = s.beginTransaction();
|
||||||
|
try {
|
||||||
|
final ChildEntity child = s.find( ChildEntity.class, 1L );
|
||||||
|
|
||||||
|
final SimpleEntity parent = child.getParent();
|
||||||
|
|
||||||
|
// assert we have an uninitialized proxy
|
||||||
|
assertTrue( parent instanceof HibernateProxy );
|
||||||
|
assertFalse( Hibernate.isInitialized( parent ) );
|
||||||
|
|
||||||
|
// Load the target of the proxy without the proxy being made aware of it
|
||||||
|
s.detach( parent );
|
||||||
|
s.find( SimpleEntity.class, 1L );
|
||||||
|
s.update( parent );
|
||||||
|
|
||||||
|
// assert we still have an uninitialized proxy
|
||||||
|
assertFalse( Hibernate.isInitialized( parent ) );
|
||||||
|
|
||||||
|
// serialize/deserialize the proxy
|
||||||
|
final SimpleEntity deserializedParent = (SimpleEntity) SerializationHelper.clone( parent );
|
||||||
|
|
||||||
|
// assert the deserialized object is no longer a proxy, but the target of the proxy
|
||||||
|
assertFalse( deserializedParent instanceof HibernateProxy );
|
||||||
|
assertEquals( "TheParent", deserializedParent.getName() );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( t.isActive() ) {
|
||||||
|
t.rollback();
|
||||||
|
}
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that lazy loading without transaction nor open session is generally
|
* Tests that lazy loading without transaction nor open session is generally
|
||||||
* working. The magic is done by {@link AbstractLazyInitializer} who opens a
|
* working. The magic is done by {@link AbstractLazyInitializer} who opens a
|
||||||
|
|
Loading…
Reference in New Issue