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,
|
||||
* 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.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.MarkerObject;
|
||||
import org.hibernate.proxy.AbstractLazyInitializer;
|
||||
|
@ -91,17 +90,11 @@ public abstract class BasicLazyInitializer extends AbstractLazyInitializer {
|
|||
}
|
||||
|
||||
private Object getReplacement() {
|
||||
final SharedSessionContractImplementor session = getSession();
|
||||
if ( isUninitialized() && 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 );
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
initializeWithoutLoadIfPossible();
|
||||
|
||||
if ( isUninitialized() ) {
|
||||
if ( replacement == null ) {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.serialization;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Entity;
|
||||
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
|
||||
* working. The magic is done by {@link AbstractLazyInitializer} who opens a
|
||||
|
|
Loading…
Reference in New Issue