47
47
import org .hibernate .engine .spi .SessionImplementor ;
48
48
import org .hibernate .engine .spi .Status ;
49
49
import org .hibernate .engine .spi .TypedValue ;
50
+ import org .hibernate .internal .CoreLogging ;
51
+ import org .hibernate .internal .CoreMessageLogger ;
50
52
import org .hibernate .internal .SessionFactoryRegistry ;
51
53
import org .hibernate .internal .util .MarkerObject ;
52
54
import org .hibernate .internal .util .collections .EmptyIterator ;
56
58
import org .hibernate .pretty .MessageHelper ;
57
59
import org .hibernate .type .ComponentType ;
58
60
import org .hibernate .type .Type ;
59
- import org .jboss .logging .Logger ;
60
61
61
62
/**
62
63
* Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
63
64
*
64
65
* @author Gavin King
65
66
*/
66
67
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 );
68
69
69
70
private transient SessionImplementor session ;
70
71
private boolean initialized ;
@@ -269,7 +270,7 @@ else if ( !session.isConnected() ) {
269
270
( (Session ) session ).close ();
270
271
}
271
272
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" );
273
274
}
274
275
session = originalSession ;
275
276
}
@@ -601,6 +602,9 @@ public final boolean unsetSession(SessionImplementor currentSession) {
601
602
return true ;
602
603
}
603
604
else {
605
+ if ( this .session != null ) {
606
+ LOG .logCannotUnsetUnexpectedSessionInCollection ( generateUnexpectedSessionStateMessage ( currentSession ) );
607
+ }
604
608
return false ;
605
609
}
606
610
}
@@ -620,28 +624,23 @@ protected void prepareForPossibleLoadingOutsideTransaction() {
620
624
}
621
625
}
622
626
623
-
624
627
@ Override
625
628
public final boolean setCurrentSession (SessionImplementor session ) throws HibernateException {
626
629
if ( session == this .session ) {
627
630
return false ;
628
631
}
629
632
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 () ) {
633
636
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
635
638
);
636
639
}
637
640
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 ;
645
644
}
646
645
}
647
646
else {
@@ -651,6 +650,46 @@ public final boolean setCurrentSession(SessionImplementor session) throws Hibern
651
650
}
652
651
}
653
652
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 ( "\n Collection contents: [" ).append ( collectionContents ).append ( "]" );
689
+ }
690
+ return sb .toString ();
691
+ }
692
+
654
693
@ Override
655
694
public boolean needsRecreate (CollectionPersister persister ) {
656
695
// Workaround for situations like HHH-7072. If the collection element is a component that consists entirely
0 commit comments