Skip to content

Commit f45e3db

Browse files
committed
HHH-18552 clean up inappropriate usages of TransientObjectException
and minor cleanups in StatefulPersistenceContext Signed-off-by: Gavin King <[email protected]>
1 parent 7422c18 commit f45e3db

File tree

13 files changed

+90
-99
lines changed

13 files changed

+90
-99
lines changed

hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,9 @@ public static Object getEntityIdentifierIfNotUnsaved(
373373

374374
private static void throwIfTransient(String entityName, Object object, SharedSessionContractImplementor session) {
375375
if ( isTransient( entityName, object, Boolean.FALSE, session ) ) {
376-
throw new TransientObjectException(
377-
"object references an unsaved transient instance - save the transient instance before flushing: " +
378-
(entityName == null ? session.guessEntityName(object) : entityName)
379-
);
376+
throw new TransientObjectException( "Entity references an unsaved transient instance of '"
377+
+ (entityName == null ? session.guessEntityName(object) : entityName)
378+
+ "' (make the transient instance persistent before flushing)" );
380379
}
381380
}
382381

hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.hibernate.MappingException;
3434
import org.hibernate.NonUniqueObjectException;
3535
import org.hibernate.PersistentObjectException;
36-
import org.hibernate.TransientObjectException;
3736
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
3837
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
3938
import org.hibernate.collection.spi.PersistentCollection;
@@ -79,6 +78,7 @@
7978
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
8079
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
8180
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
81+
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
8282

8383
/**
8484
* A <em>stateful</em> implementation of the {@link PersistenceContext} contract, meaning that we maintain this
@@ -217,7 +217,7 @@ public boolean hasLoadContext() {
217217
//
218218
@Override
219219
public PersistentCollection<?> useUnownedCollection(CollectionKey key) {
220-
return ( unownedCollections == null ) ? null : unownedCollections.remove( key );
220+
return unownedCollections == null ? null : unownedCollections.remove( key );
221221
}
222222

223223
@Override
@@ -234,7 +234,7 @@ public void clear() {
234234
//Strictly avoid lambdas in this case
235235
for ( EntityHolderImpl value : entitiesByKey.values() ) {
236236
if ( value != null && value.proxy != null ) {
237-
HibernateProxy.extractLazyInitializer( value.proxy ).unsetSession();
237+
extractLazyInitializer( value.proxy ).unsetSession();
238238
}
239239
}
240240
}
@@ -337,9 +337,8 @@ public Object getNaturalIdSnapshot(Object id, EntityPersister persister) throws
337337
if ( cachedValue != null ) {
338338
return cachedValue;
339339
}
340-
341340
// check to see if the natural id is mutable/immutable
342-
if ( persister.getEntityMetamodel().hasImmutableNaturalId() ) {
341+
else if ( persister.getEntityMetamodel().hasImmutableNaturalId() ) {
343342
// an immutable natural-id is not retrieved during a normal database-snapshot operation...
344343
final Object naturalIdFromDb = persister.getNaturalIdentifierSnapshot( id, session );
345344
naturalIdResolutions.cacheResolutionFromLoad( id, naturalIdFromDb, persister );
@@ -353,13 +352,14 @@ public Object getNaturalIdSnapshot(Object id, EntityPersister persister) throws
353352
if ( entitySnapshot == NO_ROW || entitySnapshot == null ) {
354353
return null;
355354
}
356-
357-
final Object[] naturalIdSnapshotSubSet = new Object[ props.length ];
358-
for ( int i = 0; i < props.length; i++ ) {
359-
naturalIdSnapshotSubSet[i] = entitySnapshot[ props[i] ];
355+
else {
356+
final Object[] naturalIdSnapshotSubSet = new Object[ props.length ];
357+
for ( int i = 0; i < props.length; i++ ) {
358+
naturalIdSnapshotSubSet[i] = entitySnapshot[ props[i] ];
359+
}
360+
naturalIdResolutions.cacheResolutionFromLoad( id, naturalIdSnapshotSubSet, persister );
361+
return naturalIdSnapshotSubSet;
360362
}
361-
naturalIdResolutions.cacheResolutionFromLoad( id, naturalIdSnapshotSubSet, persister );
362-
return naturalIdSnapshotSubSet;
363363
}
364364
}
365365

@@ -429,9 +429,8 @@ public boolean containsEntityHolder(EntityKey key) {
429429
public void postLoad(JdbcValuesSourceProcessingState processingState, Consumer<EntityHolder> holderConsumer) {
430430
final Callback callback = processingState.getExecutionContext().getCallback();
431431
if ( processingState.getLoadingEntityHolders() != null ) {
432-
final EventListenerGroup<PostLoadEventListener> listenerGroup = getSession().getFactory()
433-
.getFastSessionServices()
434-
.eventListenerGroup_POST_LOAD;
432+
final EventListenerGroup<PostLoadEventListener> listenerGroup =
433+
getSession().getFactory().getFastSessionServices().eventListenerGroup_POST_LOAD;
435434
final PostLoadEvent postLoadEvent = processingState.getPostLoadEvent();
436435
for ( final EntityHolder holder : processingState.getLoadingEntityHolders() ) {
437436
processLoadedEntityHolder( holder, listenerGroup, postLoadEvent, callback, holderConsumer );
@@ -460,26 +459,27 @@ private void processLoadedEntityHolder(
460459
// in which case we added an entry with a null proxy and entity.
461460
// Remove that empty entry on post load to avoid unwanted side effects
462461
entitiesByKey.remove( holder.getEntityKey() );
463-
return;
464462
}
465-
if ( postLoadEvent != null ) {
466-
postLoadEvent.reset();
467-
postLoadEvent.setEntity( holder.getEntity() )
468-
.setId( holder.getEntityKey().getIdentifier() )
469-
.setPersister( holder.getDescriptor() );
470-
listenerGroup.fireEventOnEachListener(
471-
postLoadEvent,
472-
PostLoadEventListener::onPostLoad
473-
);
474-
}
475-
if ( callback != null ) {
476-
callback.invokeAfterLoadActions(
477-
holder.getEntity(),
478-
holder.getDescriptor(),
479-
getSession()
480-
);
463+
else {
464+
if ( postLoadEvent != null ) {
465+
postLoadEvent.reset();
466+
postLoadEvent.setEntity( holder.getEntity() )
467+
.setId( holder.getEntityKey().getIdentifier() )
468+
.setPersister( holder.getDescriptor() );
469+
listenerGroup.fireEventOnEachListener(
470+
postLoadEvent,
471+
PostLoadEventListener::onPostLoad
472+
);
473+
}
474+
if ( callback != null ) {
475+
callback.invokeAfterLoadActions(
476+
holder.getEntity(),
477+
holder.getDescriptor(),
478+
getSession()
479+
);
480+
}
481+
( (EntityHolderImpl) holder ).entityInitializer = null;
481482
}
482-
( (EntityHolderImpl) holder ).entityInitializer = null;
483483
}
484484

485485
@Override
@@ -498,7 +498,8 @@ public EntityHolder addEntityHolder(EntityKey key, Object entity) {
498498
holder = oldHolder;
499499
}
500500
else {
501-
entityHolderMap.put( key, holder = EntityHolderImpl.forEntity( key, key.getPersister(), entity ) );
501+
holder = EntityHolderImpl.forEntity( key, key.getPersister(), entity );
502+
entityHolderMap.put( key, holder );
502503
}
503504
holder.state = EntityHolderState.INITIALIZED;
504505
final BatchFetchQueue fetchQueue = this.batchFetchQueue;
@@ -614,8 +615,8 @@ public EntityEntry addEntity(
614615
final boolean existsInDatabase,
615616
final EntityPersister persister,
616617
final boolean disableVersionIncrement) {
617-
EntityHolder entityHolder = addEntityHolder( entityKey, entity );
618-
EntityEntry entityEntry = addEntry(
618+
final EntityHolder entityHolder = addEntityHolder( entityKey, entity );
619+
final EntityEntry entityEntry = addEntry(
619620
entity,
620621
status,
621622
loadedState,
@@ -661,7 +662,7 @@ public EntityEntry addEntry(
661662
removes the virtual call, and allows the methods to be inlined. In this critical code path, it has a very
662663
large impact on performance to make virtual method calls.
663664
*/
664-
if (persister.getEntityEntryFactory() instanceof MutableEntityEntryFactory) {
665+
if ( persister.getEntityEntryFactory() instanceof MutableEntityEntryFactory ) {
665666
//noinspection RedundantCast
666667
e = ( (MutableEntityEntryFactory) persister.getEntityEntryFactory() ).createEntityEntry(
667668
status,
@@ -731,7 +732,7 @@ public boolean reassociateIfUninitializedProxy(Object value) throws MappingExcep
731732
if ( ! Hibernate.isInitialized( value ) ) {
732733

733734
// could be a proxy....
734-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( value );
735+
final LazyInitializer lazyInitializer = extractLazyInitializer( value );
735736
if ( lazyInitializer != null ) {
736737
reassociateProxy( lazyInitializer, asHibernateProxy( value ) );
737738
return true;
@@ -740,7 +741,8 @@ public boolean reassociateIfUninitializedProxy(Object value) throws MappingExcep
740741
// or an uninitialized enhanced entity ("bytecode proxy")...
741742
if ( isPersistentAttributeInterceptable( value ) ) {
742743
final PersistentAttributeInterceptable bytecodeProxy = asPersistentAttributeInterceptable( value );
743-
final BytecodeLazyAttributeInterceptor interceptor = (BytecodeLazyAttributeInterceptor) bytecodeProxy.$$_hibernate_getInterceptor();
744+
final BytecodeLazyAttributeInterceptor interceptor =
745+
(BytecodeLazyAttributeInterceptor) bytecodeProxy.$$_hibernate_getInterceptor();
744746
if ( interceptor != null ) {
745747
interceptor.setSession( getSession() );
746748
}
@@ -754,7 +756,7 @@ public boolean reassociateIfUninitializedProxy(Object value) throws MappingExcep
754756

755757
@Override
756758
public void reassociateProxy(Object value, Object id) throws MappingException {
757-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( value );
759+
final LazyInitializer lazyInitializer = extractLazyInitializer( value );
758760
if ( lazyInitializer != null ) {
759761
LOG.debugf( "Setting proxy identifier: %s", id );
760762
lazyInitializer.setIdentifier( id );
@@ -792,7 +794,7 @@ private void reassociateProxy(LazyInitializer li, HibernateProxy proxy) {
792794

793795
@Override
794796
public Object unproxy(Object maybeProxy) throws HibernateException {
795-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( maybeProxy );
797+
final LazyInitializer lazyInitializer = extractLazyInitializer( maybeProxy );
796798
if ( lazyInitializer != null ) {
797799
if ( lazyInitializer.isUninitialized() ) {
798800
throw new PersistentObjectException(
@@ -809,7 +811,7 @@ public Object unproxy(Object maybeProxy) throws HibernateException {
809811

810812
@Override
811813
public Object unproxyAndReassociate(final Object maybeProxy) throws HibernateException {
812-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( maybeProxy );
814+
final LazyInitializer lazyInitializer = extractLazyInitializer( maybeProxy );
813815
if ( lazyInitializer != null ) {
814816
reassociateProxy( lazyInitializer, asHibernateProxy( maybeProxy ) );
815817
//initialize + unwrap the object and return it
@@ -858,7 +860,7 @@ public Object narrowProxy(Object proxy, EntityPersister persister, EntityKey key
858860

859861
// Similarly, if the original HibernateProxy is initialized, there
860862
// is again no point in creating a proxy. Just return the impl
861-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy );
863+
final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
862864
if ( !lazyInitializer.isUninitialized() ) {
863865
final Object impl = lazyInitializer.getImplementation();
864866
// can we return it?
@@ -871,16 +873,13 @@ public Object narrowProxy(Object proxy, EntityPersister persister, EntityKey key
871873

872874
// Otherwise, create the narrowed proxy
873875
final HibernateProxy narrowedProxy = asHibernateProxy( persister.createProxy( key.getIdentifier(), session ) );
874-
875876
// set the read-only/modifiable mode in the new proxy to what it was in the original proxy
876-
final boolean readOnlyOrig = lazyInitializer.isReadOnly();
877-
narrowedProxy.getHibernateLazyInitializer().setReadOnly( readOnlyOrig );
878-
877+
narrowedProxy.getHibernateLazyInitializer().setReadOnly( lazyInitializer.isReadOnly() );
879878
return narrowedProxy;
880879
}
881880
else {
882881
if ( object != null ) {
883-
HibernateProxy.extractLazyInitializer( proxy ).setImplementation( object );
882+
extractLazyInitializer( proxy ).setImplementation( object );
884883
}
885884
return proxy;
886885
}
@@ -1531,7 +1530,7 @@ && isFoundInParent( propertyName, childEntity, persister, collectionPersister, p
15311530
if ( mergeMap != null ) {
15321531
for ( Object o : mergeMap.entrySet() ) {
15331532
final Entry<?,?> mergeMapEntry = (Entry<?,?>) o;
1534-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( mergeMapEntry.getKey() );
1533+
final LazyInitializer lazyInitializer = extractLazyInitializer( mergeMapEntry.getKey() );
15351534
if ( lazyInitializer != null ) {
15361535
if ( persister.isSubclassEntityName( lazyInitializer.getEntityName() ) ) {
15371536
HibernateProxy proxy = asHibernateProxy( mergeMapEntry.getKey() );
@@ -1693,17 +1692,17 @@ private void clearNullProperties() {
16931692
@Override
16941693
public boolean isReadOnly(Object entityOrProxy) {
16951694
if ( entityOrProxy == null ) {
1696-
throw new AssertionFailure( "object must be non-null." );
1695+
throw new IllegalArgumentException( "Null entity instance" );
16971696
}
16981697
boolean isReadOnly;
1699-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityOrProxy );
1698+
final LazyInitializer lazyInitializer = extractLazyInitializer( entityOrProxy );
17001699
if ( lazyInitializer != null ) {
17011700
isReadOnly = lazyInitializer.isReadOnly();
17021701
}
17031702
else {
17041703
final EntityEntry ee = getEntry( entityOrProxy );
17051704
if ( ee == null ) {
1706-
throw new TransientObjectException( "Instance was not associated with this persistence context" );
1705+
throw new IllegalArgumentException( "Instance is not associated with this persistence context" );
17071706
}
17081707
isReadOnly = ee.isReadOnly();
17091708
}
@@ -1713,12 +1712,12 @@ public boolean isReadOnly(Object entityOrProxy) {
17131712
@Override
17141713
public void setReadOnly(Object object, boolean readOnly) {
17151714
if ( object == null ) {
1716-
throw new AssertionFailure( "object must be non-null." );
1715+
throw new IllegalArgumentException( "Null entity instance" );
17171716
}
17181717
if ( isReadOnly( object ) == readOnly ) {
17191718
return;
17201719
}
1721-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
1720+
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
17221721
if ( lazyInitializer != null ) {
17231722
setProxyReadOnly( lazyInitializer, readOnly );
17241723
if ( ! lazyInitializer.isUninitialized() ) {
@@ -1733,7 +1732,7 @@ public void setReadOnly(Object object, boolean readOnly) {
17331732
// PersistenceContext.proxyFor( entity ) returns entity if there is no proxy for that entity
17341733
// so need to check the return value to be sure it is really a proxy
17351734
final Object maybeProxy = getSession().getPersistenceContextInternal().proxyFor( object );
1736-
final LazyInitializer lazyInitializer1 = HibernateProxy.extractLazyInitializer( maybeProxy );
1735+
final LazyInitializer lazyInitializer1 = extractLazyInitializer( maybeProxy );
17371736
if ( lazyInitializer1 != null ) {
17381737
setProxyReadOnly( lazyInitializer1, readOnly );
17391738
}
@@ -1751,7 +1750,7 @@ private void setProxyReadOnly(LazyInitializer hibernateLazyInitializer, boolean
17511750
private void setEntityReadOnly(Object entity, boolean readOnly) {
17521751
final EntityEntry entry = getEntry( entity );
17531752
if ( entry == null ) {
1754-
throw new TransientObjectException( "Instance was not associated with this persistence context" );
1753+
throw new IllegalArgumentException( "Instance was not associated with this persistence context" );
17551754
}
17561755
entry.setReadOnly( readOnly, entity );
17571756
hasNonReadOnlyEntities = hasNonReadOnlyEntities || ! readOnly;
@@ -1963,7 +1962,7 @@ public static StatefulPersistenceContext deserialize(
19631962
final EntityHolderImpl holder = EntityHolderImpl.forEntity( ek, persister, entity );
19641963
holder.state = state;
19651964
if ( proxy != null ) {
1966-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy );
1965+
final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
19671966
if ( lazyInitializer != null ) {
19681967
lazyInitializer.setSession( session );
19691968
holder.proxy = proxy;

hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,8 @@ public void executeActions() throws HibernateException {
502502
final String path = transientEntities.getNonNullableTransientPropertyPaths(transientEntity).iterator().next();
503503
//TODO: should be TransientPropertyValueException
504504
throw new TransientObjectException( "Persistent instance of '" + insertAction.getEntityName()
505-
+ "' with id '" + insertAction.getId()
506-
+ "' references an unsaved transient instance via attribute '" + path
505+
+ "' with id [" + insertAction.getId()
506+
+ "] references an unsaved transient instance via attribute '" + path
507507
+ "' (save the transient instance before flushing)" );
508508
}
509509

hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingActions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ public void cascade(
339339
boolean isCascadeDeleteEnabled)
340340
throws HibernateException {
341341
if ( child != null && isChildTransient( session, child, entityName ) ) {
342-
throw new TransientObjectException( "persistent instance references an unsaved transient instance of '"
342+
throw new TransientObjectException( "Persistent instance references an unsaved transient instance of '"
343343
+ entityName + "' (save the transient instance before flushing)" );
344344
//TODO: should be TransientPropertyValueException
345345
// throw new TransientPropertyValueException(

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ private void deleteTransientInstance(DeleteEvent event, DeleteContext transientE
179179

180180
final Object id = persister.getIdentifier( entity, source );
181181
if ( id == null ) {
182-
throw new TransientObjectException("the detached instance passed to delete() had a null identifier");
182+
throw new TransientObjectException( "Cannot delete instance of entity '" + persister.getEntityName()
183+
+ "' because it has a null identifier" );
183184
}
184185

185186
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLockEventListener.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ public void onLock(LockEvent event) throws HibernateException {
7171
final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
7272
final Object id = persister.getIdentifier( entity, source );
7373
if ( !ForeignKeys.isNotTransient( event.getEntityName(), entity, Boolean.FALSE, source ) ) {
74-
throw new TransientObjectException( "cannot lock an unsaved transient instance: "
75-
+ persister.getEntityName() );
74+
throw new TransientObjectException( "Cannot lock unsaved transient instance of entity '"
75+
+ persister.getEntityName() + "'" );
7676
}
7777
entry = reassociate( event, entity, id, persister );
7878
cascadeOnLock( event, persister, entity );

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.hibernate.engine.spi.ActionQueue;
2121
import org.hibernate.engine.spi.CascadingActions;
2222
import org.hibernate.engine.spi.EntityEntry;
23-
import org.hibernate.engine.spi.EntityKey;
2423
import org.hibernate.engine.spi.PersistenceContext;
2524
import org.hibernate.engine.spi.SessionFactoryImplementor;
2625
import org.hibernate.event.spi.EventSource;
@@ -132,7 +131,8 @@ private static void refresh(RefreshEvent event, RefreshContext refreshedAlready,
132131
persister = source.getEntityPersister( event.getEntityName(), object );
133132
id = persister.getIdentifier( object, event.getSession() );
134133
if ( id == null ) {
135-
throw new TransientObjectException( "transient instance passed to refresh");
134+
throw new TransientObjectException( "Cannot refresh instance of entity '" + persister.getEntityName()
135+
+ "' because it has a null identifier" );
136136
}
137137
if ( LOG.isTraceEnabled() ) {
138138
LOG.tracev(

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultReplicateEventListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ private void doReplicate(ReplicateEvent event, EventSource source, Object entity
7777
// except null (that is, even ids which look like they're unsaved)
7878
final Object id = persister.getIdentifier( entity, source );
7979
if ( id == null ) {
80-
throw new TransientObjectException( "instance with null id passed to replicate()" );
80+
throw new TransientObjectException( "Cannot replicate instance of entity '" + persister.getEntityName()
81+
+ "' because it has a null identifier" );
8182
}
8283

8384
final Object oldVersion = replicationMode == ReplicationMode.EXCEPTION

0 commit comments

Comments
 (0)