HHH-7457 - Enable loading of collections thats been detached from session

(cherry picked from commit 467258cffa)
This commit is contained in:
Steve Ebersole 2012-08-07 14:51:13 -05:00
parent 98caa8e44b
commit b810f1049f
2 changed files with 262 additions and 213 deletions

View File

@ -23,20 +23,30 @@
*/
package org.hibernate.collection.internal;
import javax.naming.NamingException;
import java.io.Serializable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.*;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.EmptyIterator;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.persister.collection.CollectionPersister;
@ -44,8 +54,6 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
import javax.naming.NamingException;
/**
* Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
*
@ -100,10 +108,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
//Careful: these methods do not initialize the collection.
/**
* Is the initialized collection empty?
*/
public abstract boolean empty();
/**
* Called by any read-only method of the collection interface
*/
@ -125,8 +135,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
if ( specjLazyLoad ) {
specialSpecjInitialization( false );
}
else
else {
throwLazyInitializationExceptionIfNotConnected();
}
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) {
@ -138,11 +149,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
finally {
if(specjLazyLoad)
if ( specjLazyLoad ) {
session = null;
}
}
}
}
read();
return false;
}
@ -153,8 +165,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
if ( specjLazyLoad ) {
specialSpecjInitialization( false );
}
else
else {
throwLazyInitializationExceptionIfNotConnected();
}
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) {
@ -165,10 +178,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
finally {
if(specjLazyLoad)
if ( specjLazyLoad ) {
session = null;
}
}
}
read();
return null;
}
@ -179,8 +193,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
if ( specjLazyLoad ) {
specialSpecjInitialization( false );
}
else
else {
throwLazyInitializationExceptionIfNotConnected();
}
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) {
@ -191,10 +206,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
finally {
if(specjLazyLoad)
if ( specjLazyLoad ) {
session = null;
}
}
}
read();
return null;
}
@ -246,6 +262,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
isConnectedToSession() &&
isInverseCollection();
}
/**
* Is this collection in a state that would allow us to
* "queue" puts? This is a special case, because of orphan
@ -257,6 +274,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
isConnectedToSession() &&
isInverseOneToManyOrNoOrphanDelete();
}
/**
* Is this collection in a state that would allow us to
* "queue" clear? This is a special case, because of orphan
@ -348,7 +366,8 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Not called by Hibernate, but used by non-JDK serialization,
* eg. SOAP libraries.
*/
public AbstractPersistentCollection() {}
public AbstractPersistentCollection() {
}
protected AbstractPersistentCollection(SessionImplementor session) {
this.session = session;
@ -394,7 +413,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/**
* Initialize the collection, if possible, wrapping any exceptions
* in a runtime exception
*
* @param writing currently obsolete
*
* @throws LazyInitializationException if we cannot initialize
*/
protected final void initialize(boolean writing) {
@ -491,6 +512,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/**
* Disassociate this collection from the given session.
*
* @return true if this was currently associated with the given session
*/
public final boolean unsetSession(SessionImplementor currentSession) {
@ -506,7 +528,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
protected void prepareForPossibleSpecialSpecjInitialization() {
if ( session != null ) {
specjLazyLoad = Boolean.parseBoolean( session.getFactory().getProperties().getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS));
specjLazyLoad = Boolean.parseBoolean(
session.getFactory()
.getProperties()
.getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS )
);
if ( specjLazyLoad && sessionFactoryUuid == null ) {
try {
@ -522,7 +548,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/**
* Associate the collection with the given session.
*
* @return false if the collection was already associated with the session
*
* @throws HibernateException if the collection was already associated
* with another open session
*/
@ -608,6 +636,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public final boolean hasQueuedOperations() {
return operationQueue != null;
}
/**
* Iterate the "queued" additions
*/
@ -615,12 +644,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
if ( hasQueuedOperations() ) {
return new Iterator() {
int i = 0;
public Object next() {
return operationQueue.get( i++ ).getAddedInstance();
}
public boolean hasNext() {
return i < operationQueue.size();
}
public void remove() {
throw new UnsupportedOperationException();
}
@ -630,6 +662,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return EmptyIterator.INSTANCE;
}
}
/**
* Iterate the "queued" additions
*/
@ -653,11 +686,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Called before inserting rows, to ensure that any surrogate keys
* are fully generated
*/
public void preInsert(CollectionPersister persister) throws HibernateException {}
public void preInsert(CollectionPersister persister) throws HibernateException {
}
/**
* Called after inserting a row, to fetch the natively generated id
*/
public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {}
public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
}
/**
* get all "orphaned" elements
*/
@ -677,6 +714,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public IteratorProxy(Iterator itr) {
this.itr = itr;
}
public boolean hasNext() {
return itr.hasNext();
}
@ -957,7 +995,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
protected interface DelayedOperation {
public void operate();
public Object getAddedInstance();
public Object getOrphan();
}

View File

@ -56,6 +56,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
private String sessionFactoryUuid;
private boolean specjLazyLoad = false;
/**
* For serialization from the non-pojo initializers (HHH-3309)
*/
@ -211,7 +212,11 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
protected void prepareForPossibleSpecialSpecjInitialization() {
if ( session != null ) {
specjLazyLoad =
Boolean.parseBoolean( session.getFactory().getProperties().getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS));
Boolean.parseBoolean(
session.getFactory()
.getProperties()
.getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS )
);
if ( specjLazyLoad && sessionFactoryUuid == null ) {
try {
@ -286,11 +291,13 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
private void errorIfReadOnlySettingNotAvailable() {
if ( session == null ) {
throw new TransientObjectException(
"Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session." );
"Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session."
);
}
if ( session.isClosed() ) {
throw new SessionException(
"Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session." );
"Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session."
);
}
}
@ -322,13 +329,14 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
/**
* Get the read-only/modifiable setting that should be put in affect when it is
* attached to a session.
*
* <p/>
* This method should only be called during serialization when read-only/modifiable setting
* is not available (i.e., isReadOnlySettingAvailable() == false)
*
* @return null, if the default setting should be used;
* true, for read-only;
* false, for modifiable
*
* @throws IllegalStateException if isReadOnlySettingAvailable() == true
*/
protected final Boolean isReadOnlyBeforeAttachedToSession() {
@ -343,12 +351,13 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
/**
* Set the read-only/modifiable setting that should be put in affect when it is
* attached to a session.
*
* <p/>
* This method should only be called during deserialization, before associating
* the proxy with a session.
*
* @param readOnlyBeforeAttachedToSession, the read-only/modifiable setting to use when
* associated with a session; null indicates that the default should be used.
*
* @throws IllegalStateException if isReadOnlySettingAvailable() == true
*/
/* package-private */