-
-
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
+ * 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.collection.internal;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
-
-import javax.naming.NamingException;
+import java.util.Map;
import org.hibernate.AssertionFailure;
+import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
+import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.TypedValue;
+import org.hibernate.internal.CoreLogging;
+import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.internal.util.MarkerObject;
-import org.hibernate.internal.util.collections.EmptyIterator;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
+import org.hibernate.resource.transaction.spi.TransactionStatus;
+import org.hibernate.type.CompositeType;
+import org.hibernate.type.IntegerType;
+import org.hibernate.type.LongType;
+import org.hibernate.type.PostgresUUIDType;
+import org.hibernate.type.StringType;
import org.hibernate.type.Type;
-import org.jboss.logging.Logger;
+import org.hibernate.type.UUIDBinaryType;
+import org.hibernate.type.UUIDCharType;
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
+import eu.etaxonomy.cdm.cache.ProxyUtils;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.taxeditor.remoting.CdmEagerLoadingException;
-import eu.etaxonomy.taxeditor.remoting.cache.ProxyUtils;
import eu.etaxonomy.taxeditor.service.ICachedCommonService;
/**
* Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
*
- * This a extended copy of the original class from hibernate. It has been extended to
+ * This is an extended copy of the original class from hibernate. It has been extended to
* allow making remote service calls to spring httpinvoker services (see section at the bottom
* of this class).
*
+ * NOTE: For updating this class to the latest hibernate version, update the serialVersionUID as
+ * described above, copy the new class to the old class BUT keep those 5 places marked with
+ * ##REMOTING-KEEP##
*
* @author Gavin King
* @author Cherian Mathew
*/
public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {
- private static final Logger log = Logger.getLogger( AbstractPersistentCollection.class );
+ private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPersistentCollection.class );
/**
* <b>IMPORTANT:</b><br>
* The correct <code>serialVersionUID</code> is the <code>stream classdesc serialVersionUID</code>
* from the error message.
*/
- private static final long serialVersionUID = 2742261122392386159L;
+ private static final long serialVersionUID = 6275967693128102740L;
- private transient SessionImplementor session;
+ private transient SharedSessionContractImplementor session;
+ private boolean isTempSession = false;
private boolean initialized;
private transient List<DelayedOperation> operationQueue;
private transient boolean directlyAccessible;
// collections detect changes made via their public interface and mark
// themselves as dirty as a performance optimization
private boolean dirty;
+ protected boolean elementRemoved;
private Serializable storedSnapshot;
private String sessionFactoryUuid;
- private boolean specjLazyLoad = false;
+ private boolean allowLoadOutsideTransaction;
+
+ /**
+ * Not called by Hibernate, but used by non-JDK serialization,
+ * eg. SOAP libraries.
+ */
+ public AbstractPersistentCollection() {
+ }
+
+ protected AbstractPersistentCollection(SharedSessionContractImplementor session) {
+ this.session = session;
+ }
+
+ /**
+ * @deprecated {@link #AbstractPersistentCollection(SharedSessionContractImplementor)} should be used instead.
+ */
+ @Deprecated
+ protected AbstractPersistentCollection(SessionImplementor session) {
+ this( (SharedSessionContractImplementor) session );
+ }
@Override
- public final String getRole() {
+ public final String getRole() {
return role;
}
@Override
- public final Serializable getKey() {
+ public final Serializable getKey() {
return key;
}
@Override
- public final boolean isUnreferenced() {
+ public final boolean isUnreferenced() {
return role == null;
}
@Override
- public final boolean isDirty() {
+ public final boolean isDirty() {
return dirty;
}
@Override
- public final void clearDirty() {
+ public boolean isElementRemoved() {
+ return elementRemoved;
+ }
+
+ @Override
+ public final void clearDirty() {
dirty = false;
+ elementRemoved = false;
}
@Override
- public final void dirty() {
+ public final void dirty() {
dirty = true;
}
@Override
- public final Serializable getStoredSnapshot() {
+ public final Serializable getStoredSnapshot() {
return storedSnapshot;
}
//Careful: these methods do not initialize the collection.
- /**
- * Is the initialized collection empty?
- */
@Override
- public abstract boolean empty();
+ public abstract boolean empty();
/**
* Called by any read-only method of the collection interface
return true;
}
else {
+ //##REMOTING-KEEP##
// In remoting we are sure that session is null
// both when using property paths and switching off conversations
if(session == null && remoting) {
- log.info("--> readSize, of " + getRole() + " with key " + getKey());
+ LOG.info("--> readSize, of " + getRole() + " with key " + getKey());
read();
} else {
- boolean isExtraLazy = withTemporarySessionIfNeeded(
- new LazyInitializationWork<Boolean>() {
- @Override
- public Boolean doWork() {
- CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
-
- if ( entry != null ) {
- CollectionPersister persister = entry.getLoadedPersister();
- if ( persister.isExtraLazy() ) {
- if ( hasQueuedOperations() ) {
- session.flush();
- }
- cachedSize = persister.getSize( entry.getLoadedKey(), session );
- return true;
- }
- else {
- read();
+ //keep formatting below to ease update to newer hibernate version
+ //##REMOTING-KEEP END##
+ final boolean isExtraLazy = withTemporarySessionIfNeeded(
+ new LazyInitializationWork<Boolean>() {
+ @Override
+ public Boolean doWork() {
+ final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
+
+ if ( entry != null ) {
+ final CollectionPersister persister = entry.getLoadedPersister();
+ if ( persister.isExtraLazy() ) {
+ if ( hasQueuedOperations() ) {
+ session.flush();
}
+ cachedSize = persister.getSize( entry.getLoadedKey(), session );
+ return true;
}
- else{
- throwLazyInitializationExceptionIfNotConnected();
+ else {
+ read();
}
- return false;
}
+ else{
+ throwLazyInitializationExceptionIfNotConnected();
+ }
+ return false;
}
- );
- if ( isExtraLazy ) {
- return true;
- }
+ }
+ );
+ if ( isExtraLazy ) {
+ return true;
+ }
}
}
}
return false;
}
+ /**
+ * TBH not sure why this is public
+ *
+ * @param <T> The java type of the return for this LazyInitializationWork
+ */
public static interface LazyInitializationWork<T> {
+ /**
+ * Do the represented work and return the result.
+ *
+ * @return The result
+ */
public T doWork();
}
private <T> T withTemporarySessionIfNeeded(LazyInitializationWork<T> lazyInitializationWork) {
- SessionImplementor originalSession = null;
- boolean isTempSession = false;
- boolean isJTA = false;
+ SharedSessionContractImplementor tempSession = null;
if ( session == null ) {
- if ( specjLazyLoad ) {
- session = openTemporarySessionForLoading();
- isTempSession = true;
+ if ( allowLoadOutsideTransaction ) {
+ tempSession = openTemporarySessionForLoading();
}
else {
throwLazyInitializationException( "could not initialize proxy - no Session" );
}
}
- else if ( !session.isOpen() ) {
- if ( specjLazyLoad ) {
- originalSession = session;
- session = openTemporarySessionForLoading();
- isTempSession = true;
+ else if ( !session.isOpenOrWaitingForAutoClose() ) {
+ if ( allowLoadOutsideTransaction ) {
+ tempSession = openTemporarySessionForLoading();
}
else {
throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
}
}
else if ( !session.isConnected() ) {
- if ( specjLazyLoad ) {
- originalSession = session;
- session = openTemporarySessionForLoading();
- isTempSession = true;
+ if ( allowLoadOutsideTransaction ) {
+ tempSession = openTemporarySessionForLoading();
}
else {
throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
}
}
- if ( isTempSession ) {
- // TODO: On the next major release, add an
- // 'isJTA' or 'getTransactionFactory' method to Session.
- /*isJTA = session.getTransactionCoordinator()
- .getTransactionContext().getTransactionEnvironment()
- .getTransactionFactory()
- .compatibleWithJtaSynchronization();*/
+ SharedSessionContractImplementor originalSession = null;
+ boolean isJTA = false;
+
+ if ( tempSession != null ) {
+ isTempSession = true;
+ originalSession = session;
+ session = tempSession;
+
isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
+
if ( !isJTA ) {
// Explicitly handle the transactions only if we're not in
// a JTA environment. A lazy loading temporary session can
// be created even if a current session and transaction are
// open (ex: session.clear() was used). We must prevent
// multiple transactions.
- ( ( Session) session ).beginTransaction();
+ ( (Session) session ).beginTransaction();
}
- session.getPersistenceContext().addUninitializedDetachedCollection(
+ session.getPersistenceContextInternal().addUninitializedDetachedCollection(
session.getFactory().getCollectionPersister( getRole() ),
this
);
return lazyInitializationWork.doWork();
}
finally {
- if ( isTempSession ) {
+ if ( tempSession != null ) {
// make sure the just opened temp session gets closed!
+ isTempSession = false;
+ session = originalSession;
+
try {
if ( !isJTA ) {
- ( ( Session) session ).getTransaction().commit();
+ ( (Session) tempSession ).getTransaction().commit();
}
- ( (Session) session ).close();
+ ( (Session) tempSession ).close();
}
catch (Exception e) {
- log.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
+ LOG.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
}
- session = originalSession;
}
}
}
- private SessionImplementor openTemporarySessionForLoading() {
+ private SharedSessionContractImplementor openTemporarySessionForLoading() {
if ( sessionFactoryUuid == null ) {
throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
}
- SessionFactoryImplementor sf = (SessionFactoryImplementor)
+ final SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
- return (SessionImplementor) sf.openSession();
+ final SharedSessionContractImplementor session = (SharedSessionContractImplementor) sf.openSession();
+ session.getPersistenceContextInternal().setDefaultReadOnly( true );
+ session.setFlushMode( FlushMode.MANUAL );
+ return session;
}
protected Boolean readIndexExistence(final Object index) {
if ( !initialized ) {
+ //##REMOTING-KEEP##
// In remoting we are sure that session is null
// both when using property paths and switching off conversations
if(session == null && remoting) {
- log.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
+ LOG.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
read();
} else {
- Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
- new LazyInitializationWork<Boolean>() {
- @Override
- public Boolean doWork() {
- CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
- CollectionPersister persister = entry.getLoadedPersister();
- if ( persister.isExtraLazy() ) {
- if ( hasQueuedOperations() ) {
- session.flush();
- }
- return persister.indexExists( entry.getLoadedKey(), index, session );
- }
- else {
- read();
+ //keep formatting below to ease update to newer hibernate version
+ //##REMOTING-KEEP END##
+ final Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
+ new LazyInitializationWork<Boolean>() {
+ @Override
+ public Boolean doWork() {
+ final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
+ final CollectionPersister persister = entry.getLoadedPersister();
+ if ( persister.isExtraLazy() ) {
+ if ( hasQueuedOperations() ) {
+ session.flush();
}
- return null;
+ return persister.indexExists( entry.getLoadedKey(), index, session );
}
+ else {
+ read();
+ }
+ return null;
}
- );
- if ( extraLazyExistenceCheck != null ) {
- return extraLazyExistenceCheck;
- }
+ }
+ );
+ if ( extraLazyExistenceCheck != null ) {
+ return extraLazyExistenceCheck;
+ }
}
}
return null;
protected Boolean readElementExistence(final Object element) {
if ( !initialized ) {
+ //##REMOTING-KEEP##
// In remoting we are sure that session is null
// both when using property paths and switching off conversations
if(session == null && remoting) {
- log.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
+ LOG.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
read();
} else {
- Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
- new LazyInitializationWork<Boolean>() {
- @Override
- public Boolean doWork() {
- CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
- CollectionPersister persister = entry.getLoadedPersister();
- if ( persister.isExtraLazy() ) {
- if ( hasQueuedOperations() ) {
- session.flush();
- }
- return persister.elementExists( entry.getLoadedKey(), element, session );
- }
- else {
- read();
+ //keep formatting below to ease update to newer hibernate version
+ //##REMOTING-KEEP END##
+ final Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
+ new LazyInitializationWork<Boolean>() {
+ @Override
+ public Boolean doWork() {
+ final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
+ final CollectionPersister persister = entry.getLoadedPersister();
+ if ( persister.isExtraLazy() ) {
+ if ( hasQueuedOperations() ) {
+ session.flush();
}
- return null;
+ return persister.elementExists( entry.getLoadedKey(), element, session );
}
+ else {
+ read();
+ }
+ return null;
}
- );
- if ( extraLazyExistenceCheck != null ) {
- return extraLazyExistenceCheck;
- }
+ }
+ );
+ if ( extraLazyExistenceCheck != null ) {
+ return extraLazyExistenceCheck;
+ }
}
}
return null;
protected Object readElementByIndex(final Object index) {
if ( !initialized ) {
+ //##REMOTING-KEEP##
// In remoting we are sure that session is null
// both when using property paths and switching off conversations
if(session == null && remoting) {
- log.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
+ LOG.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
read();
} else {
- class ExtraLazyElementByIndexReader implements LazyInitializationWork {
- private boolean isExtraLazy;
- private Object element;
+ //keep formatting below to ease update to newer hibernate version
+ //##REMOTING-KEEP END##
+ class ExtraLazyElementByIndexReader implements LazyInitializationWork {
+ private boolean isExtraLazy;
+ private Object element;
- @Override
- public Object doWork() {
- CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
- CollectionPersister persister = entry.getLoadedPersister();
- isExtraLazy = persister.isExtraLazy();
- if ( isExtraLazy ) {
- if ( hasQueuedOperations() ) {
- session.flush();
- }
- element = persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
- }
- else {
- read();
+ @Override
+ public Object doWork() {
+ final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
+ final CollectionPersister persister = entry.getLoadedPersister();
+ isExtraLazy = persister.isExtraLazy();
+ if ( isExtraLazy ) {
+ if ( hasQueuedOperations() ) {
+ session.flush();
}
- return null;
+ element = persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
+ }
+ else {
+ read();
}
+ return null;
}
+ }
- ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
- //noinspection unchecked
- withTemporarySessionIfNeeded( reader );
- if ( reader.isExtraLazy ) {
- return reader.element;
- }
+ final ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
+ //noinspection unchecked
+ withTemporarySessionIfNeeded( reader );
+ if ( reader.isExtraLazy ) {
+ return reader.element;
+ }
}
}
return UNKNOWN;
return cachedSize;
}
- private boolean isConnectedToSession() {
- return session != null &&
- session.isOpen() &&
- session.getPersistenceContext().containsCollection( this );
+ protected boolean isConnectedToSession() {
+ return session != null
+ && session.isOpen()
+ && session.getPersistenceContextInternal().containsCollection( this );
+ }
+
+ protected boolean isInitialized() {
+ return initialized;
}
/**
*/
@SuppressWarnings({"JavaDoc"})
protected boolean isOperationQueueEnabled() {
- return !initialized &&
- isConnectedToSession() &&
- isInverseCollection();
+ return !initialized
+ && isConnectedToSession()
+ && isInverseCollection();
}
/**
*/
@SuppressWarnings({"JavaDoc"})
protected boolean isPutQueueEnabled() {
- return !initialized &&
- isConnectedToSession() &&
- isInverseOneToManyOrNoOrphanDelete();
+ return !initialized
+ && isConnectedToSession()
+ && isInverseOneToManyOrNoOrphanDelete();
}
/**
*/
@SuppressWarnings({"JavaDoc"})
protected boolean isClearQueueEnabled() {
- return !initialized &&
- isConnectedToSession() &&
- isInverseCollectionNoOrphanDelete();
+ return !initialized
+ && isConnectedToSession()
+ && isInverseCollectionNoOrphanDelete();
}
/**
* Is this the "inverse" end of a bidirectional association?
*/
@SuppressWarnings({"JavaDoc"})
- private boolean isInverseCollection() {
- CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
+ protected boolean isInverseCollection() {
+ final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
return ce != null && ce.getLoadedPersister().isInverse();
}
* no orphan delete enabled?
*/
@SuppressWarnings({"JavaDoc"})
- private boolean isInverseCollectionNoOrphanDelete() {
- CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
- return ce != null &&
- ce.getLoadedPersister().isInverse() &&
- !ce.getLoadedPersister().hasOrphanDelete();
+ protected boolean isInverseCollectionNoOrphanDelete() {
+ final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
+ if ( ce == null ) {
+ return false;
+ }
+ final CollectionPersister loadedPersister = ce.getLoadedPersister();
+ return loadedPersister.isInverse() && !loadedPersister.hasOrphanDelete();
}
/**
* of a collection with no orphan delete?
*/
@SuppressWarnings({"JavaDoc"})
- private boolean isInverseOneToManyOrNoOrphanDelete() {
- CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
- return ce != null && ce.getLoadedPersister().isInverse() && (
- ce.getLoadedPersister().isOneToMany() ||
- !ce.getLoadedPersister().hasOrphanDelete()
- );
+ protected boolean isInverseOneToManyOrNoOrphanDelete() {
+ final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
+ if ( ce == null ) {
+ return false;
+ }
+ final CollectionPersister loadedPersister = ce.getLoadedPersister();
+ return loadedPersister.isInverse() && ( loadedPersister.isOneToMany() || !loadedPersister.hasOrphanDelete() );
}
/**
operationQueue = new ArrayList<DelayedOperation>( 10 );
}
operationQueue.add( operation );
- dirty = true; //needed so that we remove this collection from the second-level cache
+ //needed so that we remove this collection from the second-level cache
+ dirty = true;
+ }
+
+ /**
+ * Replace entity instances with copy in {@code copyCache}/.
+ *
+ * @param copyCache - mapping from entity in the process of being
+ * merged to managed copy.
+ */
+ public final void replaceQueuedOperationValues(CollectionPersister persister, Map copyCache) {
+ for ( DelayedOperation operation : operationQueue ) {
+ if ( ValueDelayedOperation.class.isInstance( operation ) ) {
+ ( (ValueDelayedOperation) operation ).replace( persister, copyCache );
+ }
+ }
}
/**
for ( DelayedOperation operation : operationQueue ) {
operation.operate();
}
+ clearOperationQueue();
}
- /**
- * After flushing, re-init snapshot state.
- */
@Override
- public void setSnapshot(Serializable key, String role, Serializable snapshot) {
+ public void setSnapshot(Serializable key, String role, Serializable snapshot) {
this.key = key;
this.role = role;
this.storedSnapshot = snapshot;
}
- /**
- * After flushing, clear any "queued" additions, since the
- * database state is now synchronized with the memory state.
- */
@Override
- public void postAction() {
- operationQueue = null;
+ public void postAction() {
+ clearOperationQueue();
cachedSize = -1;
clearDirty();
}
- /**
- * Not called by Hibernate, but used by non-JDK serialization,
- * eg. SOAP libraries.
- */
- public AbstractPersistentCollection() {
- }
-
- protected AbstractPersistentCollection(SessionImplementor session) {
- this.session = session;
+ public final void clearOperationQueue() {
+ operationQueue = null;
}
- /**
- * return the user-visible collection (or array) instance
- */
@Override
- public Object getValue() {
+ public Object getValue() {
return this;
}
- /**
- * Called just before reading any rows from the JDBC result set
- */
@Override
- public void beginRead() {
+ public void beginRead() {
// override on some subclasses
initializing = true;
}
- /**
- * Called after reading all rows from the JDBC result set
- */
@Override
- public boolean endRead() {
+ public boolean endRead() {
//override on some subclasses
return afterInitialize();
}
@Override
- public boolean afterInitialize() {
+ public boolean afterInitialize() {
setInitialized();
//do this bit after setting initialized to true or it will recurse
- if ( operationQueue != null ) {
+ if ( hasQueuedOperations() ) {
performQueuedOperations();
- operationQueue = null;
cachedSize = -1;
return false;
}
* @throws LazyInitializationException if we cannot initialize
*/
protected final void initialize(final boolean writing) {
- if ( initialized ) {
- return;
- }
-
+ if ( initialized ) {
+ return;
+ }
+ //##REMOTING-KEEP##
// In remoting we are sure that session is null
// both when using property paths and switching off conversations
if(session == null && remoting) {
remoteInitialize();
} else {
- withTemporarySessionIfNeeded(
- new LazyInitializationWork<Object>() {
- @Override
- public Object doWork() {
- session.initializeCollection( AbstractPersistentCollection.this, writing );
- return null;
- }
- }
- );
+ //keep formatting below to ease update to newer hibernate version
+ //##REMOTING-KEEP END##
+ withTemporarySessionIfNeeded(
+ new LazyInitializationWork<Object>() {
+ @Override
+ public Object doWork() {
+ session.initializeCollection( AbstractPersistentCollection.this, writing );
+ return null;
+ }
+ }
+ );
}
}
this.directlyAccessible = directlyAccessible;
}
- /**
- * Could the application possibly have a direct reference to
- * the underlying collection implementation?
- */
@Override
- public boolean isDirectlyAccessible() {
+ public boolean isDirectlyAccessible() {
return directlyAccessible;
}
- /**
- * Disassociate this collection from the given session.
- *
- * @return true if this was currently associated with the given session
- */
@Override
- public final boolean unsetSession(SessionImplementor currentSession) {
- prepareForPossibleSpecialSpecjInitialization();
+ public final boolean unsetSession(SharedSessionContractImplementor currentSession) {
+ prepareForPossibleLoadingOutsideTransaction();
if ( currentSession == this.session ) {
- this.session = null;
+ if ( !isTempSession ) {
+ if ( hasQueuedOperations() ) {
+ final String collectionInfoString = MessageHelper.collectionInfoString( getRole(), getKey() );
+ try {
+ final TransactionStatus transactionStatus =
+ session.getTransactionCoordinator().getTransactionDriverControl().getStatus();
+ if ( transactionStatus.isOneOf(
+ TransactionStatus.ROLLED_BACK,
+ TransactionStatus.MARKED_ROLLBACK,
+ TransactionStatus.FAILED_COMMIT,
+ TransactionStatus.FAILED_ROLLBACK,
+ TransactionStatus.ROLLING_BACK
+ ) ) {
+ // It was due to a rollback.
+ LOG.queuedOperationWhenDetachFromSessionOnRollback( collectionInfoString );
+ }
+ else {
+ // We don't know why the collection is being detached.
+ // Just log the info.
+ LOG.queuedOperationWhenDetachFromSession( collectionInfoString );
+ }
+ }
+ catch (Exception e) {
+ // We don't know why the collection is being detached.
+ // Just log the info.
+ LOG.queuedOperationWhenDetachFromSession( collectionInfoString );
+ }
+ }
+ if ( allowLoadOutsideTransaction && !initialized && session.getLoadQueryInfluencers().hasEnabledFilters() ) {
+ final String collectionInfoString = MessageHelper.collectionInfoString( getRole(), getKey() );
+ LOG.enabledFiltersWhenDetachFromSession( collectionInfoString );
+ }
+ this.session = null;
+ }
return true;
}
else {
+ if ( this.session != null ) {
+ LOG.logCannotUnsetUnexpectedSessionInCollection( generateUnexpectedSessionStateMessage( currentSession ) );
+ }
return false;
}
}
- protected void prepareForPossibleSpecialSpecjInitialization() {
+ protected void prepareForPossibleLoadingOutsideTransaction() {
if ( session != null ) {
- specjLazyLoad = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
+ allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled();
- if ( specjLazyLoad && sessionFactoryUuid == null ) {
- try {
- sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
- }
- catch (NamingException e) {
- //not much we can do if this fails...
- }
+ if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) {
+ sessionFactoryUuid = session.getFactory().getUuid();
}
}
}
-
- /**
- * 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
- */
@Override
- public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
+ public final boolean setCurrentSession(SharedSessionContractImplementor session) throws HibernateException {
if ( session == this.session ) {
return false;
}
- else {
+ else if ( this.session != null ) {
+ final String msg = generateUnexpectedSessionStateMessage( session );
if ( isConnectedToSession() ) {
- CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
- if ( ce == null ) {
- throw new HibernateException(
- "Illegal attempt to associate a collection with two open sessions"
- );
- }
- else {
- throw new HibernateException(
- "Illegal attempt to associate a collection with two open sessions: " +
- MessageHelper.collectionInfoString(
- ce.getLoadedPersister(), this,
- ce.getLoadedKey(), session
- )
- );
- }
+ throw new HibernateException(
+ "Illegal attempt to associate a collection with two open sessions. " + msg
+ );
}
else {
- this.session = session;
- return true;
+ LOG.logUnexpectedSessionInCollectionNotConnected( msg );
}
}
+ if ( hasQueuedOperations() ) {
+ LOG.queuedOperationWhenAttachToSession( MessageHelper.collectionInfoString( getRole(), getKey() ) );
+ }
+ this.session = session;
+ return true;
+ }
+
+ private String generateUnexpectedSessionStateMessage(SharedSessionContractImplementor session) {
+ // NOTE: If this.session != null, this.session may be operating on this collection
+ // (e.g., by changing this.role, this.key, or even this.session) in a different thread.
+
+ // Grab the current role and key (it can still get changed by this.session...)
+ // If this collection is connected to this.session, then this.role and this.key should
+ // be consistent with the CollectionEntry in this.session (as long as this.session doesn't
+ // change it). Don't access the CollectionEntry in this.session because that could result
+ // in multi-threaded access to this.session.
+ final String roleCurrent = role;
+ final Serializable keyCurrent = key;
+
+ final StringBuilder sb = new StringBuilder( "Collection : " );
+ if ( roleCurrent != null ) {
+ sb.append( MessageHelper.collectionInfoString( roleCurrent, keyCurrent ) );
+ }
+ else {
+ final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
+ if ( ce != null ) {
+ sb.append(
+ MessageHelper.collectionInfoString(
+ ce.getLoadedPersister(),
+ this,
+ ce.getLoadedKey(),
+ session
+ )
+ );
+ }
+ else {
+ sb.append( "<unknown>" );
+ }
+ }
+ // only include the collection contents if debug logging
+ if ( LOG.isDebugEnabled() ) {
+ final String collectionContents = wasInitialized() ? toString() : "<uninitialized>";
+ sb.append( "\nCollection contents: [" ).append( collectionContents ).append( "]" );
+ }
+ return sb.toString();
}
- /**
- * Do we need to completely recreate this collection when it changes?
- */
@Override
- public boolean needsRecreate(CollectionPersister persister) {
+ public boolean needsRecreate(CollectionPersister persister) {
+ // Workaround for situations like HHH-7072. If the collection element is a component that consists entirely
+ // of nullable properties, we currently have to forcefully recreate the entire collection. See the use
+ // of hasNotNullableColumns in the AbstractCollectionPersister constructor for more info. In order to delete
+ // row-by-row, that would require SQL like "WHERE ( COL = ? OR ( COL is null AND ? is null ) )", rather than
+ // the current "WHERE COL = ?" (fails for null for most DBs). Note that
+ // the param would have to be bound twice. Until we eventually add "parameter bind points" concepts to the
+ // AST in ORM 5+, handling this type of condition is either extremely difficult or impossible. Forcing
+ // recreation isn't ideal, but not really any other option in ORM 4.
+ // Selecting a type used in where part of update statement
+ // (must match condition in org.hibernate.persister.collection.BasicCollectionPersister#doUpdateRows).
+ // See HHH-9474
+ Type whereType;
+ if ( persister.hasIndex() ) {
+ whereType = persister.getIndexType();
+ }
+ else {
+ whereType = persister.getElementType();
+ }
+ if ( whereType instanceof CompositeType ) {
+ CompositeType componentIndexType = (CompositeType) whereType;
+ return !componentIndexType.hasNotNullProperty();
+ }
return false;
}
- /**
- * To be called internally by the session, forcing
- * immediate initialization.
- */
@Override
- public final void forceInitialization() throws HibernateException {
+ public final void forceInitialization() throws HibernateException {
if ( !initialized ) {
if ( initializing ) {
throw new AssertionFailure( "force initialize loading collection" );
}
- if ( session == null ) {
- throw new HibernateException( "collection is not associated with any session" );
- }
- if ( !session.isConnected() ) {
- throw new HibernateException( "disconnected session" );
- }
- session.initializeCollection( this, false );
+ initialize( false );
}
}
return session.getPersistenceContext().getSnapshot( this );
}
- /**
- * Is this instance initialized?
- */
@Override
- public final boolean wasInitialized() {
+ public final boolean wasInitialized() {
return initialized;
}
@Override
- public boolean isRowUpdatePossible() {
+ public boolean isRowUpdatePossible() {
return true;
}
- /**
- * Does this instance have any "queued" additions?
- */
@Override
- public final boolean hasQueuedOperations() {
+ public final boolean hasQueuedOperations() {
return operationQueue != null;
}
- /**
- * Iterate the "queued" additions
- */
@Override
- public final Iterator queuedAdditionIterator() {
+ public final Iterator queuedAdditionIterator() {
if ( hasQueuedOperations() ) {
return new Iterator() {
- int i = 0;
+ private int index;
@Override
- public Object next() {
- return operationQueue.get( i++ ).getAddedInstance();
+ public Object next() {
+ return operationQueue.get( index++ ).getAddedInstance();
}
@Override
- public boolean hasNext() {
- return i < operationQueue.size();
+ public boolean hasNext() {
+ return index < operationQueue.size();
}
@Override
- public void remove() {
+ public void remove() {
throw new UnsupportedOperationException();
}
};
}
else {
- return EmptyIterator.INSTANCE;
+ return Collections.emptyIterator();
}
}
- /**
- * Iterate the "queued" additions
- */
@Override
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked"})
public final Collection getQueuedOrphans(String entityName) {
if ( hasQueuedOperations() ) {
- Collection additions = new ArrayList( operationQueue.size() );
- Collection removals = new ArrayList( operationQueue.size() );
+ final Collection additions = new ArrayList( operationQueue.size() );
+ final Collection removals = new ArrayList( operationQueue.size() );
for ( DelayedOperation operation : operationQueue ) {
additions.add( operation.getAddedInstance() );
removals.add( operation.getOrphan() );
}
}
- /**
- * Called before inserting rows, to ensure that any surrogate keys
- * are fully generated
- */
@Override
- 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
- */
@Override
- 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
- */
@Override
- public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
+ public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
/**
- * Get the current session
+ * Get the session currently associated with this collection.
+ *
+ * @return The session
*/
- @SuppressWarnings({"JavaDoc"})
- public final SessionImplementor getSession() {
+ public final SharedSessionContractImplementor getSession() {
return session;
}
}
@Override
- public boolean hasNext() {
+ public boolean hasNext() {
return itr.hasNext();
}
@Override
- public Object next() {
+ public Object next() {
return itr.next();
}
@Override
- public void remove() {
+ public void remove() {
write();
itr.remove();
}
-
}
protected final class ListIteratorProxy implements ListIterator {
}
@Override
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked"})
public void add(Object o) {
write();
itr.add( o );
}
@Override
- public boolean hasNext() {
+ public boolean hasNext() {
return itr.hasNext();
}
@Override
- public boolean hasPrevious() {
+ public boolean hasPrevious() {
return itr.hasPrevious();
}
@Override
- public Object next() {
+ public Object next() {
return itr.next();
}
@Override
- public int nextIndex() {
+ public int nextIndex() {
return itr.nextIndex();
}
@Override
- public Object previous() {
+ public Object previous() {
return itr.previous();
}
@Override
- public int previousIndex() {
+ public int previousIndex() {
return itr.previousIndex();
}
@Override
- public void remove() {
+ public void remove() {
write();
itr.remove();
}
@Override
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked"})
public void set(Object o) {
write();
itr.set( o );
}
-
}
protected class SetProxy implements java.util.Set {
}
@Override
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked"})
public boolean add(Object o) {
write();
return set.add( o );
}
@Override
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked"})
public boolean addAll(Collection c) {
write();
return set.addAll( c );
}
@Override
- public void clear() {
+ public void clear() {
write();
set.clear();
}
@Override
- public boolean contains(Object o) {
+ public boolean contains(Object o) {
return set.contains( o );
}
@Override
- public boolean containsAll(Collection c) {
+ @SuppressWarnings("unchecked")
+ public boolean containsAll(Collection c) {
return set.containsAll( c );
}
@Override
- public boolean isEmpty() {
+ public boolean isEmpty() {
return set.isEmpty();
}
@Override
- public Iterator iterator() {
+ public Iterator iterator() {
return new IteratorProxy( set.iterator() );
}
@Override
- public boolean remove(Object o) {
+ public boolean remove(Object o) {
write();
return set.remove( o );
}
@Override
- public boolean removeAll(Collection c) {
+ @SuppressWarnings("unchecked")
+ public boolean removeAll(Collection c) {
write();
return set.removeAll( c );
}
@Override
- public boolean retainAll(Collection c) {
+ @SuppressWarnings("unchecked")
+ public boolean retainAll(Collection c) {
write();
return set.retainAll( c );
}
@Override
- public int size() {
+ public int size() {
return set.size();
}
@Override
- public Object[] toArray() {
+ public Object[] toArray() {
return set.toArray();
}
@Override
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked"})
public Object[] toArray(Object[] array) {
return set.toArray( array );
}
-
}
protected final class ListProxy implements java.util.List {
}
@Override
+ @SuppressWarnings("unchecked")
public boolean containsAll(Collection c) {
return list.containsAll( c );
}
}
@Override
+ @SuppressWarnings("unchecked")
public boolean removeAll(Collection c) {
write();
return list.removeAll( c );
}
@Override
+ @SuppressWarnings("unchecked")
public boolean retainAll(Collection c) {
write();
return list.retainAll( c );
public Object getOrphan();
}
+ protected interface ValueDelayedOperation extends DelayedOperation {
+ void replace(CollectionPersister collectionPersister, Map copyCache);
+ }
+
+ protected abstract class AbstractValueDelayedOperation implements ValueDelayedOperation {
+ private Object addedValue;
+ private Object orphan;
+
+ protected AbstractValueDelayedOperation(Object addedValue, Object orphan) {
+ this.addedValue = addedValue;
+ this.orphan = orphan;
+ }
+
+ @Override
+ public void replace(CollectionPersister persister, Map copyCache) {
+ if ( addedValue != null ) {
+ addedValue = getReplacement( persister.getElementType(), addedValue, copyCache );
+ }
+ }
+
+ protected final Object getReplacement(Type type, Object current, Map copyCache) {
+ return type.replace( current, null, session, owner, copyCache );
+ }
+
+ @Override
+ public final Object getAddedInstance() {
+ return addedValue;
+ }
+
+ @Override
+ public final Object getOrphan() {
+ return orphan;
+ }
+ }
+
/**
* Given a collection of entity instances that used to
* belong to the collection, and a collection of instances
Collection oldElements,
Collection currentElements,
String entityName,
- SessionImplementor session) throws HibernateException {
+ SharedSessionContractImplementor session) throws HibernateException {
// short-circuit(s)
if ( currentElements.size() == 0 ) {
- return oldElements; // no new elements, the old list contains only Orphans
+ // no new elements, the old list contains only Orphans
+ return oldElements;
}
if ( oldElements.size() == 0 ) {
- return oldElements; // no old elements, so no Orphans neither
+ // no old elements, so no Orphans neither
+ return oldElements;
}
final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
final Type idType = entityPersister.getIdentifierType();
+ final boolean useIdDirect = mayUseIdDirect( idType );
// create the collection holding the Orphans
- Collection res = new ArrayList();
+ final Collection res = new ArrayList();
// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
- java.util.Set currentIds = new HashSet();
- java.util.Set currentSaving = new IdentitySet();
+ final java.util.Set currentIds = new HashSet();
+ final java.util.Set currentSaving = new IdentitySet();
+ final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
for ( Object current : currentElements ) {
if ( current != null && ForeignKeys.isNotTransient( entityName, current, null, session ) ) {
- EntityEntry ee = session.getPersistenceContext().getEntry( current );
+ final EntityEntry ee = persistenceContext.getEntry( current );
if ( ee != null && ee.getStatus() == Status.SAVING ) {
currentSaving.add( current );
}
else {
- Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
+ final Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
entityName,
current,
session
);
- currentIds.add( new TypedValue( idType, currentId, entityPersister.getEntityMode() ) );
+ currentIds.add( useIdDirect ? currentId : new TypedValue( idType, currentId ) );
}
}
}
// iterate over the *old* list
for ( Object old : oldElements ) {
if ( !currentSaving.contains( old ) ) {
- Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
- if ( !currentIds.contains( new TypedValue( idType, oldId, entityPersister.getEntityMode() ) ) ) {
+ final Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
+ if ( !currentIds.contains( useIdDirect ? oldId : new TypedValue( idType, oldId ) ) ) {
res.add( old );
}
}
return res;
}
+ private static boolean mayUseIdDirect(Type idType) {
+ return idType == StringType.INSTANCE
+ || idType == IntegerType.INSTANCE
+ || idType == LongType.INSTANCE
+ || idType == UUIDBinaryType.INSTANCE
+ || idType == UUIDCharType.INSTANCE
+ || idType == PostgresUUIDType.INSTANCE;
+ }
+
+ /**
+ * Removes entity entries that have an equal identifier with the incoming entity instance
+ *
+ * @param list The list containing the entity instances
+ * @param entityInstance The entity instance to match elements.
+ * @param entityName The entity name
+ * @param session The session
+ */
public static void identityRemove(
Collection list,
- Object object,
+ Object entityInstance,
String entityName,
- SessionImplementor session) throws HibernateException {
+ SharedSessionContractImplementor session) {
- if ( object != null && ForeignKeys.isNotTransient( entityName, object, null, session ) ) {
+ if ( entityInstance != null && ForeignKeys.isNotTransient( entityName, entityInstance, null, session ) ) {
final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
- Type idType = entityPersister.getIdentifierType();
+ final Type idType = entityPersister.getIdentifierType();
- Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, object, session );
- Iterator itr = list.iterator();
+ final Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, entityInstance, session );
+ final Iterator itr = list.iterator();
while ( itr.hasNext() ) {
- Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
+ final Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
if ( idType.isEqual( idOfCurrent, idOfOld, session.getFactory() ) ) {
itr.remove();
break;
}
}
+ /**
+ * Removes entity entries that have an equal identifier with the incoming entity instance
+ *
+ * @param list The list containing the entity instances
+ * @param entityInstance The entity instance to match elements.
+ * @param entityName The entity name
+ * @param session The session
+ *
+ * @deprecated {@link #identityRemove(Collection, Object, String, SharedSessionContractImplementor)}
+ * should be used instead.
+ */
+ @Deprecated
+ public static void identityRemove(
+ Collection list,
+ Object entityInstance,
+ String entityName,
+ SessionImplementor session) {
+ identityRemove( list, entityInstance, entityName, (SharedSessionContractImplementor) session );
+ }
+
@Override
- public Object getIdentifier(Object entry, int i) {
+ public Object getIdentifier(Object entry, int i) {
throw new UnsupportedOperationException();
}
@Override
- public Object getOwner() {
+ public Object getOwner() {
return owner;
}
@Override
- public void setOwner(Object owner) {
+ public void setOwner(Object owner) {
this.owner = owner;
}
- /** ------ Below is section of code which makes remote service calls ----- */
- // The affected methods are :
- // initialize(final boolean writing)
- // readSize()
- // readIndexExistence(final Object index)
- // readElementExistence(final Object element)
- // readElementByIndex(final Object index)
+
+/** ##REMOTING-KEEP## #######################################################
+
+ ADDED PART: Below is the section of code which makes remote service calls.
+ Keeps this code when upgrading to newer hibernate version. Also keep
+ other code marked with ##REMOTING-KEEP## in the following 5 methods:
+
+ {@link #initialize(boolean)}
+ {@link #readSize()}
+ {@link #readIndexExistence(Object)}
+ {@link #readElementExistence(Object)}
+ {@link #readElementByIndex(Object)}
+
+ ######################################################################### */
private static CdmApplicationRemoteConfiguration configuration;
private static boolean remoting = false;
configuration = conf;
}
-
private void remoteInitialize() {
if (getOwner() != null && !initialized) {
-
+ Object collectionType = null;
+ Field field = null;
+ Class<?> clazz = null;
try {
String role = getRole();
String fieldName = role.substring(role.lastIndexOf(".") + 1);
- log.info("--> Remote Lazy Initializing Collection " + getRole() + " , owner : " + getOwner().getClass() + "/" + getKey() + " , field : " + fieldName);
+ LOG.info("--> Remote Lazy Initializing Collection " + getRole() + " , owner : " + getOwner().getClass() + "/" + getKey() + " , field : " + fieldName);
Object owner = getOwner();
CdmBase cdmBase;
if(owner instanceof CdmBase) {
throw new HibernateException("commonService not initialized (null)");
}
- //Object obj = ProxyUtils.deproxy(cachedCommonService.initializeCollection(this));
- Object obj = ProxyUtils.deproxy(cachedCommonService.initializeCollection(cdmBase.getUuid(), fieldName));
- if(ProxyUtils.isProxy(obj)) {
+ //Object obj = ProxyUtils.deproxyIfInitialized(cachedCommonService.initializeCollection(this));
+ Object obj = ProxyUtils.deproxyIfInitialized(cachedCommonService.initializeCollection(cdmBase.getUuid(), fieldName));
+ if(ProxyUtils.isUninitializedProxy(obj)) {
throw new HibernateException("Persistent Collection initialized but is still a proxy");
}
afterInitialize();
- Class<?> clazz = getClass();
+ clazz = getClass();
if (clazz != null) {
- //CollectionField cf = cachedCommonService.getCollectionField(col);
- //cachedCommonService.updatePersistentCollection(cf);
- Object collectionType = ProxyUtils.getCollectionType(obj);
- Field field = clazz.getDeclaredField(collectionType.toString());
+ collectionType = ProxyUtils.getCollectionType(obj, clazz);
+ field = clazz.getDeclaredField(collectionType.toString());
field.setAccessible(true);
field.set(this, obj);
ProxyUtils.setRoleValueInOwner(owner, role, obj);
}
} catch (Exception ex) {
- throw new CdmEagerLoadingException(ex);
+ String originalMessage = ex.getMessage();
+ String message = originalMessage + "clazz: " + (clazz == null? "" :clazz.getSimpleName())+ "- field: " + field + " - collectionType: " + collectionType;
+ throw new CdmEagerLoadingException(message);
}
}
}
-
-
-
-}
-
+ // ##REMOTING-KEEP END##
+}
\ No newline at end of file