1515import org .hibernate .engine .spi .SessionFactoryImplementor ;
1616import org .hibernate .engine .spi .SessionImplementor ;
1717import org .hibernate .event .spi .EventSource ;
18+ import org .hibernate .internal .CoreLogging ;
1819import org .hibernate .internal .CoreMessageLogger ;
1920import org .hibernate .persister .collection .CollectionPersister ;
20- import org .hibernate .pretty .MessageHelper ;
2121import org .hibernate .type .CollectionType ;
2222
23- import org .jboss .logging .Logger ;
24-
25- import java .lang .invoke .MethodHandles ;
23+ import static org .hibernate .pretty .MessageHelper .collectionInfoString ;
2624
2725/**
2826 * Implements book-keeping for the collection persistence by reachability algorithm
2927 *
3028 * @author Gavin King
3129 */
3230public final class Collections {
33- private static final CoreMessageLogger LOG = Logger .getMessageLogger (
34- MethodHandles .lookup (),
35- CoreMessageLogger .class ,
36- Collections .class .getName ()
37- );
31+ private static final CoreMessageLogger LOG = CoreLogging .messageLogger ( Collections .class );
3832
3933 /**
4034 * record the fact that this collection was dereferenced
@@ -57,46 +51,25 @@ private static void processDereferencedCollection(PersistentCollection<?> coll,
5751 final CollectionPersister loadedPersister = entry .getLoadedPersister ();
5852
5953 if ( loadedPersister != null && LOG .isDebugEnabled () ) {
60- LOG .debugf (
61- "Collection dereferenced: %s" ,
62- MessageHelper .collectionInfoString ( loadedPersister ,
63- coll , entry .getLoadedKey (), session
64- )
65- );
54+ LOG .debug ("Collection dereferenced: "
55+ + collectionInfoString ( loadedPersister , coll , entry .getLoadedKey (), session ) );
6656 }
6757
6858 // do a check
6959 final boolean hasOrphanDelete = loadedPersister != null && loadedPersister .hasOrphanDelete ();
7060 if ( hasOrphanDelete ) {
71- Object ownerId = loadedPersister .getOwnerEntityPersister ().getIdentifier ( coll .getOwner (), session );
72- if ( ownerId == null ) {
73- // the owning entity may have been deleted and its identifier unset due to
74- // identifier-rollback; in which case, try to look up its identifier from
75- // the persistence context
76- if ( session .getFactory ().getSessionFactoryOptions ().isIdentifierRollbackEnabled () ) {
77- final EntityEntry ownerEntry = persistenceContext .getEntry ( coll .getOwner () );
78- if ( ownerEntry != null ) {
79- ownerId = ownerEntry .getId ();
80- }
81- }
82- if ( ownerId == null ) {
83- throw new AssertionFailure ( "Unable to determine collection owner identifier for orphan-delete processing" );
84- }
85- }
61+ final Object ownerId = getOwnerId ( coll , session , loadedPersister );
8662 final EntityKey key = session .generateEntityKey ( ownerId , loadedPersister .getOwnerEntityPersister () );
8763 final Object owner = persistenceContext .getEntity ( key );
8864 if ( owner == null ) {
89- throw new AssertionFailure (
90- "collection owner not associated with session: " +
91- loadedPersister .getRole ()
92- );
65+ throw new AssertionFailure ( "collection owner not associated with session: " + loadedPersister .getRole () );
9366 }
9467 final EntityEntry e = persistenceContext .getEntry ( owner );
9568 //only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
9669 if ( e != null && !e .getStatus ().isDeletedOrGone () ) {
9770 throw new HibernateException (
98- "A collection with orphan deletion was no longer referenced by the owning entity instance: " +
99- loadedPersister .getRole ()
71+ "A collection with orphan deletion was no longer referenced by the owning entity instance: "
72+ + loadedPersister .getRole ()
10073 );
10174 }
10275 }
@@ -108,21 +81,43 @@ private static void processDereferencedCollection(PersistentCollection<?> coll,
10881
10982 }
11083
84+ private static Object getOwnerId (
85+ PersistentCollection <?> coll ,
86+ SessionImplementor session ,
87+ CollectionPersister loadedPersister ) {
88+
89+ Object ownerId =
90+ loadedPersister .getOwnerEntityPersister ()
91+ .getIdentifier ( coll .getOwner (), session );
92+ if ( ownerId == null ) {
93+ // the owning entity may have been deleted and its identifier unset due to
94+ // identifier-rollback; in which case, try to look up its identifier from
95+ // the persistence context
96+ if ( session .getFactory ().getSessionFactoryOptions ()
97+ .isIdentifierRollbackEnabled () ) {
98+ final EntityEntry ownerEntry =
99+ session .getPersistenceContextInternal ()
100+ .getEntry ( coll .getOwner () );
101+ if ( ownerEntry != null ) {
102+ ownerId = ownerEntry .getId ();
103+ }
104+ }
105+ if ( ownerId == null ) {
106+ throw new AssertionFailure ( "Unable to determine collection owner identifier for orphan delete processing" );
107+ }
108+ }
109+ return ownerId ;
110+ }
111+
111112 private static void processNeverReferencedCollection (PersistentCollection <?> coll , SessionImplementor session )
112113 throws HibernateException {
113- final PersistenceContext persistenceContext = session .getPersistenceContextInternal ();
114- final CollectionEntry entry = persistenceContext .getCollectionEntry ( coll );
114+ final CollectionEntry entry =
115+ session .getPersistenceContextInternal ()
116+ .getCollectionEntry ( coll );
115117
116118 if ( LOG .isDebugEnabled () ) {
117- LOG .debugf (
118- "Found collection with unloaded owner: %s" ,
119- MessageHelper .collectionInfoString (
120- entry .getLoadedPersister (),
121- coll ,
122- entry .getLoadedKey (),
123- session
124- )
125- );
119+ LOG .debug ( "Found collection with unloaded owner: " +
120+ collectionInfoString ( entry .getLoadedPersister (), coll , entry .getLoadedKey (), session ) );
126121 }
127122
128123 entry .setCurrentPersister ( entry .getLoadedPersister () );
@@ -146,34 +141,34 @@ public static void processReachableCollection(
146141 Object entity ,
147142 SessionImplementor session ) {
148143 collection .setOwner ( entity );
149- final CollectionEntry ce = session .getPersistenceContextInternal ().getCollectionEntry ( collection );
144+ final CollectionEntry ce =
145+ session .getPersistenceContextInternal ()
146+ .getCollectionEntry ( collection );
150147
151148 if ( ce == null ) {
152149 // refer to comment in StatefulPersistenceContext.addCollection()
153- throw new HibernateException (
154- "Found two representations of same collection: " +
155- type .getRole ()
156- );
150+ throw new HibernateException ( "Found two representations of same collection: " + type .getRole () );
157151 }
158152
159153 final SessionFactoryImplementor factory = session .getFactory ();
160- final CollectionPersister persister = factory . getRuntimeMetamodels ()
161- .getMappingMetamodel ()
162- .getCollectionDescriptor ( type .getRole () );
154+ final CollectionPersister persister =
155+ factory .getMappingMetamodel ()
156+ .getCollectionDescriptor ( type .getRole () );
163157
164158 ce .setCurrentPersister ( persister );
165159 //TODO: better to pass the id in as an argument?
166160 ce .setCurrentKey ( type .getKeyOfOwner ( entity , session ) );
167161
168- final boolean isBytecodeEnhanced = persister .getOwnerEntityPersister ().getBytecodeEnhancementMetadata ().isEnhancedForLazyLoading ();
162+ final boolean isBytecodeEnhanced =
163+ persister .getOwnerEntityPersister ()
164+ .getBytecodeEnhancementMetadata ()
165+ .isEnhancedForLazyLoading ();
169166 if ( isBytecodeEnhanced && !collection .wasInitialized () ) {
170167 // the class of the collection owner is enhanced for lazy loading and we found an un-initialized PersistentCollection
171168 // - skip it
172169 if ( LOG .isDebugEnabled () ) {
173- LOG .debugf (
174- "Skipping uninitialized bytecode-lazy collection: %s" ,
175- MessageHelper .collectionInfoString (persister , collection , ce .getCurrentKey (), session )
176- );
170+ LOG .debug ( "Skipping uninitialized bytecode-lazy collection: "
171+ + collectionInfoString ( persister , collection , ce .getCurrentKey (), session ) );
177172 }
178173 ce .setReached ( true );
179174 ce .setProcessed ( true );
@@ -184,9 +179,7 @@ public static void processReachableCollection(
184179 // who set up circular or shared references between/to collections.
185180 if ( ce .isReached () ) {
186181 // We've been here before
187- throw new HibernateException (
188- "Found shared references to a collection: " + type .getRole ()
189- );
182+ throw new HibernateException ( "Found shared references to a collection: " + type .getRole () );
190183 }
191184
192185 ce .setReached ( true );
@@ -195,13 +188,13 @@ public static void processReachableCollection(
195188 if ( collection .wasInitialized () ) {
196189 LOG .debugf (
197190 "Collection found: %s, was: %s (initialized)" ,
198- MessageHelper . collectionInfoString (
191+ collectionInfoString (
199192 persister ,
200193 collection ,
201194 ce .getCurrentKey (),
202195 session
203196 ),
204- MessageHelper . collectionInfoString (
197+ collectionInfoString (
205198 ce .getLoadedPersister (),
206199 collection ,
207200 ce .getLoadedKey (),
@@ -212,13 +205,13 @@ public static void processReachableCollection(
212205 else {
213206 LOG .debugf (
214207 "Collection found: %s, was: %s (uninitialized)" ,
215- MessageHelper . collectionInfoString (
208+ collectionInfoString (
216209 persister ,
217210 collection ,
218211 ce .getCurrentKey (),
219212 session
220213 ),
221- MessageHelper . collectionInfoString (
214+ collectionInfoString (
222215 ce .getLoadedPersister (),
223216 collection ,
224217 ce .getLoadedKey (),
@@ -250,25 +243,21 @@ private static void prepareCollectionForUpdate(
250243 if ( loadedPersister != null || currentPersister != null ) {
251244 // it is or was referenced _somewhere_
252245
253- // check if the key changed
254- // excludes marking key changed when the loaded key is a DelayedPostInsertIdentifier.
255- final boolean keyChanged = currentPersister != null
256- && entry != null
257- && !currentPersister .getKeyType ().isEqual ( entry .getLoadedKey (), entry .getCurrentKey (), factory )
258- && !( entry .getLoadedKey () instanceof DelayedPostInsertIdentifier );
259246
260247 // if either its role changed, or its key changed
261- final boolean ownerChanged = loadedPersister != currentPersister || keyChanged ;
248+ final boolean ownerChanged =
249+ loadedPersister != currentPersister
250+ || wasKeyChanged ( entry , factory , currentPersister );
262251
263252 if ( ownerChanged ) {
264253 // do a check
265254 final boolean orphanDeleteAndRoleChanged =
266255 loadedPersister != null && currentPersister != null && loadedPersister .hasOrphanDelete ();
267256
268- if (orphanDeleteAndRoleChanged ) {
257+ if ( orphanDeleteAndRoleChanged ) {
269258 throw new HibernateException (
270- "Don't change the reference to a collection with delete- orphan enabled : "
271- + loadedPersister .getRole ()
259+ "Don't change the reference to a collection with delete orphan enabled: "
260+ + loadedPersister .getRole ()
272261 );
273262 }
274263
@@ -293,6 +282,17 @@ else if ( collection.isDirty() ) {
293282 }
294283 }
295284
285+ /**
286+ * Check if the key changed.
287+ * Excludes marking key changed when the loaded key is a {@code DelayedPostInsertIdentifier}.
288+ */
289+ private static boolean wasKeyChanged (
290+ CollectionEntry entry , SessionFactoryImplementor factory , CollectionPersister currentPersister ) {
291+ return currentPersister != null
292+ && !currentPersister .getKeyType ().isEqual ( entry .getLoadedKey (), entry .getCurrentKey (), factory )
293+ && !(entry .getLoadedKey () instanceof DelayedPostInsertIdentifier );
294+ }
295+
296296 /**
297297 * Determines if we can skip the explicit SQL delete statement, since
298298 * the rows will be deleted by {@code on delete cascade}.
0 commit comments