Skip to content

Commit 0854a04

Browse files
committed
HHH-9518 : Exception handling around collection session access needs to be improved
(cherry picked from commit f4f0490) Conflicts: hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java HHH-9518 : Corrections to test to work for pre-5.0
1 parent 5ed5934 commit 0854a04

File tree

3 files changed

+756
-15
lines changed

3 files changed

+756
-15
lines changed

hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import org.hibernate.engine.spi.SessionImplementor;
4848
import org.hibernate.engine.spi.Status;
4949
import org.hibernate.engine.spi.TypedValue;
50+
import org.hibernate.internal.CoreLogging;
51+
import org.hibernate.internal.CoreMessageLogger;
5052
import org.hibernate.internal.SessionFactoryRegistry;
5153
import org.hibernate.internal.util.MarkerObject;
5254
import org.hibernate.internal.util.collections.EmptyIterator;
@@ -56,15 +58,14 @@
5658
import org.hibernate.pretty.MessageHelper;
5759
import org.hibernate.type.ComponentType;
5860
import org.hibernate.type.Type;
59-
import org.jboss.logging.Logger;
6061

6162
/**
6263
* Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
6364
*
6465
* @author Gavin King
6566
*/
6667
public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {
67-
private static final Logger log = Logger.getLogger( AbstractPersistentCollection.class );
68+
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPersistentCollection.class );
6869

6970
private transient SessionImplementor session;
7071
private boolean initialized;
@@ -269,7 +270,7 @@ else if ( !session.isConnected() ) {
269270
( (Session) session ).close();
270271
}
271272
catch (Exception e) {
272-
log.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
273+
LOG.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
273274
}
274275
session = originalSession;
275276
}
@@ -601,6 +602,9 @@ public final boolean unsetSession(SessionImplementor currentSession) {
601602
return true;
602603
}
603604
else {
605+
if ( this.session != null ) {
606+
LOG.logCannotUnsetUnexpectedSessionInCollection( generateUnexpectedSessionStateMessage( currentSession ) );
607+
}
604608
return false;
605609
}
606610
}
@@ -620,28 +624,23 @@ protected void prepareForPossibleLoadingOutsideTransaction() {
620624
}
621625
}
622626

623-
624627
@Override
625628
public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
626629
if ( session == this.session ) {
627630
return false;
628631
}
629632
else {
630-
if ( isConnectedToSession() ) {
631-
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
632-
if ( ce == null ) {
633+
if ( this.session != null ) {
634+
final String msg = generateUnexpectedSessionStateMessage( session );
635+
if ( isConnectedToSession() ) {
633636
throw new HibernateException(
634-
"Illegal attempt to associate a collection with two open sessions"
637+
"Illegal attempt to associate a collection with two open sessions. " + msg
635638
);
636639
}
637640
else {
638-
throw new HibernateException(
639-
"Illegal attempt to associate a collection with two open sessions: " +
640-
MessageHelper.collectionInfoString(
641-
ce.getLoadedPersister(), this,
642-
ce.getLoadedKey(), session
643-
)
644-
);
641+
LOG.logUnexpectedSessionInCollectionNotConnected( msg );
642+
this.session = session;
643+
return true;
645644
}
646645
}
647646
else {
@@ -651,6 +650,46 @@ public final boolean setCurrentSession(SessionImplementor session) throws Hibern
651650
}
652651
}
653652

653+
private String generateUnexpectedSessionStateMessage(SessionImplementor session) {
654+
// NOTE: If this.session != null, this.session may be operating on this collection
655+
// (e.g., by changing this.role, this.key, or even this.session) in a different thread.
656+
657+
// Grab the current role and key (it can still get changed by this.session...)
658+
// If this collection is connected to this.session, then this.role and this.key should
659+
// be consistent with the CollectionEntry in this.session (as long as this.session doesn't
660+
// change it). Don't access the CollectionEntry in this.session because that could result
661+
// in multi-threaded access to this.session.
662+
final String roleCurrent = role;
663+
final Serializable keyCurrent = key;
664+
665+
final StringBuilder sb = new StringBuilder( "Collection : " );
666+
if ( roleCurrent != null ) {
667+
sb.append( MessageHelper.collectionInfoString( roleCurrent, keyCurrent ) );
668+
}
669+
else {
670+
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
671+
if ( ce != null ) {
672+
sb.append(
673+
MessageHelper.collectionInfoString(
674+
ce.getLoadedPersister(),
675+
this,
676+
ce.getLoadedKey(),
677+
session
678+
)
679+
);
680+
}
681+
else {
682+
sb.append( "<unknown>" );
683+
}
684+
}
685+
// only include the collection contents if debug logging
686+
if ( LOG.isDebugEnabled() ) {
687+
final String collectionContents = wasInitialized() ? toString() : "<uninitialized>";
688+
sb.append( "\nCollection contents: [" ).append( collectionContents ).append( "]" );
689+
}
690+
return sb.toString();
691+
}
692+
654693
@Override
655694
public boolean needsRecreate(CollectionPersister persister) {
656695
// Workaround for situations like HHH-7072. If the collection element is a component that consists entirely

hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,4 +1680,12 @@ void cannotResolveNonNullableTransientDependencies(String transientEntityString,
16801680
@LogMessage(level = DEBUG)
16811681
@Message(value = "Creating pooled optimizer (lo) with [incrementSize=%s; returnClass=%s]", id = 467)
16821682
void creatingPooledLoOptimizer(int incrementSize, String name);
1683+
1684+
@LogMessage(level = WARN)
1685+
@Message(value = "An unexpected session is defined for a collection, but the collection is not connected to that session. A persistent collection may only be associated with one session at a time. Overwriting session. %s", id = 470)
1686+
void logUnexpectedSessionInCollectionNotConnected(String msg);
1687+
1688+
@LogMessage(level = WARN)
1689+
@Message(value = "Cannot unset session in a collection because an unexpected session is defined. A persistent collection may only be associated with one session at a time. %s", id = 471 )
1690+
void logCannotUnsetUnexpectedSessionInCollection(String msg);
16831691
}

0 commit comments

Comments
 (0)