30
30
import org .hibernate .engine .spi .SessionImplementor ;
31
31
import org .hibernate .engine .spi .Status ;
32
32
import org .hibernate .engine .spi .TypedValue ;
33
+ import org .hibernate .internal .CoreLogging ;
34
+ import org .hibernate .internal .CoreMessageLogger ;
33
35
import org .hibernate .internal .SessionFactoryRegistry ;
34
36
import org .hibernate .internal .util .MarkerObject ;
35
37
import org .hibernate .internal .util .collections .EmptyIterator ;
45
47
import org .hibernate .type .Type ;
46
48
import org .hibernate .type .UUIDBinaryType ;
47
49
import org .hibernate .type .UUIDCharType ;
48
- import org .jboss .logging .Logger ;
49
50
50
51
/**
51
52
* Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
52
53
*
53
54
* @author Gavin King
54
55
*/
55
56
public abstract class AbstractPersistentCollection implements Serializable , PersistentCollection {
56
- private static final Logger log = Logger . getLogger ( AbstractPersistentCollection .class );
57
+ private static final CoreMessageLogger LOG = CoreLogging . messageLogger ( AbstractPersistentCollection .class );
57
58
58
59
private transient SessionImplementor session ;
59
60
private boolean initialized ;
@@ -255,7 +256,7 @@ else if ( !session.isConnected() ) {
255
256
( (Session ) session ).close ();
256
257
}
257
258
catch (Exception e ) {
258
- log .warn ( "Unable to close temporary session used to load lazy collection associated to no session" );
259
+ LOG .warn ( "Unable to close temporary session used to load lazy collection associated to no session" );
259
260
}
260
261
session = originalSession ;
261
262
}
@@ -587,6 +588,9 @@ public final boolean unsetSession(SessionImplementor currentSession) {
587
588
return true ;
588
589
}
589
590
else {
591
+ if ( this .session != null ) {
592
+ LOG .logCannotUnsetUnexpectedSessionInCollection ( generateUnexpectedSessionStateMessage ( currentSession ) );
593
+ }
590
594
return false ;
591
595
}
592
596
}
@@ -606,28 +610,23 @@ protected void prepareForPossibleLoadingOutsideTransaction() {
606
610
}
607
611
}
608
612
609
-
610
613
@ Override
611
614
public final boolean setCurrentSession (SessionImplementor session ) throws HibernateException {
612
615
if ( session == this .session ) {
613
616
return false ;
614
617
}
615
618
else {
616
- if ( isConnectedToSession () ) {
617
- final CollectionEntry ce = session . getPersistenceContext (). getCollectionEntry ( this );
618
- if ( ce == null ) {
619
+ if ( this . session != null ) {
620
+ final String msg = generateUnexpectedSessionStateMessage ( session );
621
+ if ( isConnectedToSession () ) {
619
622
throw new HibernateException (
620
- "Illegal attempt to associate a collection with two open sessions"
623
+ "Illegal attempt to associate a collection with two open sessions. " + msg
621
624
);
622
625
}
623
626
else {
624
- throw new HibernateException (
625
- "Illegal attempt to associate a collection with two open sessions: " +
626
- MessageHelper .collectionInfoString (
627
- ce .getLoadedPersister (), this ,
628
- ce .getLoadedKey (), session
629
- )
630
- );
627
+ LOG .logUnexpectedSessionInCollectionNotConnected ( msg );
628
+ this .session = session ;
629
+ return true ;
631
630
}
632
631
}
633
632
else {
@@ -637,6 +636,46 @@ public final boolean setCurrentSession(SessionImplementor session) throws Hibern
637
636
}
638
637
}
639
638
639
+ private String generateUnexpectedSessionStateMessage (SessionImplementor session ) {
640
+ // NOTE: If this.session != null, this.session may be operating on this collection
641
+ // (e.g., by changing this.role, this.key, or even this.session) in a different thread.
642
+
643
+ // Grab the current role and key (it can still get changed by this.session...)
644
+ // If this collection is connected to this.session, then this.role and this.key should
645
+ // be consistent with the CollectionEntry in this.session (as long as this.session doesn't
646
+ // change it). Don't access the CollectionEntry in this.session because that could result
647
+ // in multi-threaded access to this.session.
648
+ final String roleCurrent = role ;
649
+ final Serializable keyCurrent = key ;
650
+
651
+ final StringBuilder sb = new StringBuilder ( "Collection : " );
652
+ if ( roleCurrent != null ) {
653
+ sb .append ( MessageHelper .collectionInfoString ( roleCurrent , keyCurrent ) );
654
+ }
655
+ else {
656
+ final CollectionEntry ce = session .getPersistenceContext ().getCollectionEntry ( this );
657
+ if ( ce != null ) {
658
+ sb .append (
659
+ MessageHelper .collectionInfoString (
660
+ ce .getLoadedPersister (),
661
+ this ,
662
+ ce .getLoadedKey (),
663
+ session
664
+ )
665
+ );
666
+ }
667
+ else {
668
+ sb .append ( "<unknown>" );
669
+ }
670
+ }
671
+ // only include the collection contents if debug logging
672
+ if ( LOG .isDebugEnabled () ) {
673
+ final String collectionContents = wasInitialized () ? toString () : "<uninitialized>" ;
674
+ sb .append ( "\n Collection contents: [" ).append ( collectionContents ).append ( "]" );
675
+ }
676
+ return sb .toString ();
677
+ }
678
+
640
679
@ Override
641
680
public boolean needsRecreate (CollectionPersister persister ) {
642
681
// Workaround for situations like HHH-7072. If the collection element is a component that consists entirely
0 commit comments