下面列出了怎么用org.hibernate.ObjectDeletedException的API类实例代码及写法,或者点击链接到github查看源代码。
private CompletionStage<Void> fireRemove(DeleteEvent event) {
pulseTransactionCoordinator();
return fire(event, EventType.DELETE,
(ReactiveDeleteEventListener l) -> l::reactiveOnDelete)
.handle( (v, e) -> {
delayedAfterCompletion();
if ( e instanceof ObjectDeletedException ) {
throw getExceptionConverter().convert( new IllegalArgumentException( e ) );
}
else if ( e instanceof MappingException ) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) );
}
else if ( e instanceof RuntimeException ) {
//including HibernateException
throw getExceptionConverter().convert( (RuntimeException) e );
}
return CompletionStages.returnNullorRethrow( e );
});
}
private CompletionStage<Void> fireRemove(DeleteEvent event, IdentitySet transientEntities) {
pulseTransactionCoordinator();
return fire(event, transientEntities, EventType.DELETE,
(ReactiveDeleteEventListener l) -> l::reactiveOnDelete)
.handle( (v, e) -> {
delayedAfterCompletion();
if ( e instanceof ObjectDeletedException ) {
throw getExceptionConverter().convert( new IllegalArgumentException( e ) );
}
else if ( e instanceof MappingException ) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) );
}
else if ( e instanceof RuntimeException ) {
//including HibernateException
throw getExceptionConverter().convert( (RuntimeException) e );
}
return CompletionStages.returnNullorRethrow( e );
});
}
@SuppressWarnings("unchecked")
private <T> CompletionStage<T> fireMerge(MergeEvent event) {
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
return fire(event, EventType.MERGE,
(ReactiveMergeEventListener l) -> l::reactiveOnMerge)
.handle( (v,e) -> {
checkNoUnresolvedActionsAfterOperation();
if (e instanceof ObjectDeletedException) {
throw getExceptionConverter().convert( new IllegalArgumentException( e ) );
}
else if (e instanceof MappingException) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) );
}
else if (e instanceof RuntimeException) {
//including HibernateException
throw getExceptionConverter().convert( (RuntimeException) e );
}
return CompletionStages.returnOrRethrow( e, (T) event.getResult() );
});
}
private CompletionStage<Void> fireMerge(MergeContext copiedAlready, MergeEvent event) {
pulseTransactionCoordinator();
return fire(event, copiedAlready, EventType.MERGE,
(ReactiveMergeEventListener l) -> l::reactiveOnMerge)
.handle( (v,e) -> {
delayedAfterCompletion();
if (e instanceof ObjectDeletedException) {
throw getExceptionConverter().convert( new IllegalArgumentException( e ) );
}
else if (e instanceof MappingException) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) );
}
else if (e instanceof RuntimeException) {
//including HibernateException
throw getExceptionConverter().convert( (RuntimeException) e );
}
return CompletionStages.returnNullorRethrow( e );
});
}
@Override
public LockMode getCurrentLockMode(Object object) throws HibernateException {
checkOpen();
checkTransactionSynchStatus();
if ( object == null ) {
throw new NullPointerException( "null object passed to getCurrentLockMode()" );
}
if ( object instanceof HibernateProxy ) {
object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation( this );
if ( object == null ) {
return LockMode.NONE;
}
}
EntityEntry e = persistenceContext.getEntry( object );
if ( e == null ) {
throw new TransientObjectException( "Given object not associated with the session" );
}
if ( e.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"The given object was deleted",
e.getId(),
e.getPersister().getEntityName()
);
}
return e.getLockMode();
}
@Override
public void forceFlush(EntityEntry entityEntry) throws HibernateException {
if ( log.isDebugEnabled() ) {
log.debugf(
"Flushing to force deletion of re-saved object: %s",
MessageHelper.infoString( entityEntry.getPersister(), entityEntry.getId(), getFactory() )
);
}
if ( persistenceContext.getCascadeLevel() > 0 ) {
throw new ObjectDeletedException(
"deleted object would be re-saved by cascade (remove deleted object from associations)",
entityEntry.getId(),
entityEntry.getPersister().getEntityName()
);
}
checkOpenOrWaitingForAutoClose();
doFlush();
}
protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
// this implementation is supposed to tolerate incorrect unsaved-value
// mappings, for the purpose of backward-compatibility
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
if ( entry!=null ) {
if ( entry.getStatus()== Status.DELETED ) {
throw new ObjectDeletedException( "deleted instance passed to update()", null, event.getEntityName() );
}
else {
return entityIsPersistent(event);
}
}
else {
entityIsDetached(event);
return null;
}
}
protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
// this implementation is supposed to tolerate incorrect unsaved-value
// mappings, for the purpose of backward-compatibility
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
if ( entry!=null ) {
if ( entry.getStatus()==Status.DELETED ) {
throw new ObjectDeletedException( "deleted instance passed to update()", null, event.getEntityName() );
}
else {
return entityIsPersistent(event);
}
}
else {
entityIsDetached(event);
return null;
}
}
public LockMode getCurrentLockMode(Object object) throws HibernateException {
errorIfClosed();
checkTransactionSynchStatus();
if ( object == null ) {
throw new NullPointerException( "null object passed to getCurrentLockMode()" );
}
if ( object instanceof HibernateProxy ) {
object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(this);
if ( object == null ) {
return LockMode.NONE;
}
}
EntityEntry e = persistenceContext.getEntry(object);
if ( e == null ) {
throw new TransientObjectException( "Given object not associated with the session" );
}
if ( e.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"The given object was deleted",
e.getId(),
e.getPersister().getEntityName()
);
}
return e.getLockMode();
}
public void forceFlush(EntityEntry entityEntry) throws HibernateException {
errorIfClosed();
if ( log.isDebugEnabled() ) {
log.debug(
"flushing to force deletion of re-saved object: " +
MessageHelper.infoString( entityEntry.getPersister(), entityEntry.getId(), getFactory() )
);
}
if ( persistenceContext.getCascadeLevel() > 0 ) {
throw new ObjectDeletedException(
"deleted object would be re-saved by cascade (remove deleted object from associations)",
entityEntry.getId(),
entityEntry.getPersister().getEntityName()
);
}
flush();
}
@Override
public <T> CompletionStage<T> reactiveFind(
Class<T> entityClass,
Object id,
LockMode lockMode,
Map<String, Object> properties) {
checkOpen();
getLoadQueryInfluencers().getEffectiveEntityGraph().applyConfiguredGraph( properties );
Boolean readOnly = properties == null ? null : (Boolean) properties.get( QueryHints.HINT_READONLY );
getLoadQueryInfluencers().setReadOnly( readOnly );
final ReactiveIdentifierLoadAccessImpl<T> loadAccess =
new ReactiveIdentifierLoadAccessImpl<>(entityClass)
.with( determineAppropriateLocalCacheMode( properties ) );
LockOptions lockOptions;
if ( lockMode != null ) {
// if ( !LockModeType.NONE.equals( lockModeType) ) {
// checkTransactionNeededForUpdateOperation();
// }
lockOptions = buildLockOptions(
LockModeConverter.convertToLockModeType(lockMode),
properties
);
loadAccess.with( lockOptions );
}
else {
lockOptions = null;
}
return loadAccess.load( (Serializable) id )
.handle( (result, e) -> {
if ( e instanceof EntityNotFoundException) {
// DefaultLoadEventListener.returnNarrowedProxy may throw ENFE (see HHH-7861 for details),
// which find() should not throw. Find() should return null if the entity was not found.
// if ( log.isDebugEnabled() ) {
// String entityName = entityClass != null ? entityClass.getName(): null;
// String identifierValue = id != null ? id.toString() : null ;
// log.ignoringEntityNotFound( entityName, identifierValue );
// }
return null;
}
if ( e instanceof ObjectDeletedException) {
//the spec is silent about people doing remove() find() on the same PC
return null;
}
if ( e instanceof ObjectNotFoundException) {
//should not happen on the entity itself with get
throw new IllegalArgumentException( e.getMessage(), e );
}
if ( e instanceof MappingException
|| e instanceof TypeMismatchException
|| e instanceof ClassCastException ) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) );
}
if ( e instanceof JDBCException ) {
// if ( accessTransaction().getRollbackOnly() ) {
// // assume this is the similar to the WildFly / IronJacamar "feature" described under HHH-12472
// return null;
// }
throw getExceptionConverter().convert( (JDBCException) e, lockOptions );
}
if ( e instanceof RuntimeException ) {
throw getExceptionConverter().convert( (RuntimeException) e, lockOptions );
}
return result;
} )
.whenComplete( (v, e) -> getLoadQueryInfluencers().getEffectiveEntityGraph().clear() );
}
/**
* Handle the given create event.
*
* @param event The create event to be handled.
*/
public CompletionStage<Void> reactiveOnPersist(PersistEvent event, IdentitySet createCache) throws HibernateException {
final SessionImplementor source = event.getSession();
final Object object = event.getObject();
final Object entity;
if ( object instanceof HibernateProxy ) {
LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
if ( li.isUninitialized() ) {
if ( li.getSession() == source ) {
return CompletionStages.nullFuture(); //NOTE EARLY EXIT!
}
else {
return CompletionStages.failedFuture( new PersistentObjectException( "uninitialized proxy passed to persist()" ) );
}
}
entity = li.getImplementation();
}
else {
entity = object;
}
final String entityName;
if ( event.getEntityName() != null ) {
entityName = event.getEntityName();
}
else {
entityName = source.bestGuessEntityName( entity );
event.setEntityName( entityName );
}
final EntityEntry entityEntry = source.getPersistenceContextInternal().getEntry( entity );
EntityState entityState = EntityState.getEntityState( entity, entityName, entityEntry, source, true );
if ( entityState == EntityState.DETACHED ) {
// JPA 2, in its version of a "foreign generated", allows the id attribute value
// to be manually set by the user, even though this manual value is irrelevant.
// The issue is that this causes problems with the Hibernate unsaved-value strategy
// which comes into play here in determining detached/transient state.
//
// Detect if we have this situation and if so null out the id value and calculate the
// entity state again.
// NOTE: entityEntry must be null to get here, so we cannot use any of its values
EntityPersister persister = source.getFactory().getMetamodel().entityPersister( entityName );
if (persister.getIdentifierGenerator() instanceof ForeignGenerator) {
if ( LOG.isDebugEnabled() && persister.getIdentifier( entity, source ) != null ) {
LOG.debug( "Resetting entity id attribute to null for foreign generator" );
}
persister.setIdentifier( entity, null, source );
entityState = EntityState.getEntityState( entity, entityName, entityEntry, source, true );
}
}
switch ( entityState ) {
case DETACHED: {
return CompletionStages.failedFuture( new PersistentObjectException(
"detached entity passed to persist: " +
EventUtil.getLoggableName( event.getEntityName(), entity )
) );
}
case PERSISTENT: {
return entityIsPersistent( event, createCache );
}
case TRANSIENT: {
return entityIsTransient( event, createCache );
}
case DELETED: {
entityEntry.setStatus( Status.MANAGED );
entityEntry.setDeletedState( null );
event.getSession().getActionQueue().unScheduleDeletion( entityEntry, event.getObject() );
return entityIsDeleted( event, createCache );
}
default: {
return CompletionStages.failedFuture( new ObjectDeletedException(
"deleted entity passed to persist",
null,
EventUtil.getLoggableName( event.getEntityName(), entity )
) );
}
}
}
/**
* Performs a pessimistic lock upgrade on a given entity, if needed.
*
* @param object The entity for which to upgrade the lock.
* @param entry The entity's EntityEntry instance.
* @param lockOptions contains the requested lock mode.
* @param source The session which is the source of the event being processed.
*/
protected CompletionStage<Void> upgradeLock(Object object, EntityEntry entry,
LockOptions lockOptions,
EventSource source) {
LockMode requestedLockMode = lockOptions.getLockMode();
if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
// The user requested a "greater" (i.e. more restrictive) form of
// pessimistic lock
if ( entry.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"attempted to lock a deleted instance",
entry.getId(),
entry.getPersister().getEntityName()
);
}
final EntityPersister persister = entry.getPersister();
if ( log.isTraceEnabled() ) {
log.tracev(
"Locking {0} in mode: {1}",
MessageHelper.infoString( persister, entry.getId(), source.getFactory() ),
requestedLockMode
);
}
final boolean cachingEnabled = persister.canWriteToCache();
final SoftLock lock;
final Object ck;
if ( cachingEnabled ) {
EntityDataAccess cache = persister.getCacheAccessStrategy();
ck = cache.generateCacheKey(
entry.getId(),
persister,
source.getFactory(),
source.getTenantIdentifier()
);
lock = cache.lockItem( source, ck, entry.getVersion() );
}
else {
lock = null;
ck = null;
}
return ((ReactiveEntityPersister) persister).lockReactive(
entry.getId(),
entry.getVersion(),
object,
lockOptions,
source
).thenAccept( v -> entry.setLockMode(requestedLockMode) )
.whenComplete( (r, e) -> {
// the database now holds a lock + the object is flushed from the cache,
// so release the soft lock
if ( cachingEnabled ) {
persister.getCacheAccessStrategy().unlockItem( source, ck, lock );
}
} );
}
else {
return CompletionStages.nullFuture();
}
}
/**
* Performs a pessimistic lock upgrade on a given entity, if needed.
*
* @param object The entity for which to upgrade the lock.
* @param entry The entity's EntityEntry instance.
* @param lockOptions contains the requested lock mode.
* @param source The session which is the source of the event being processed.
*/
protected void upgradeLock(Object object, EntityEntry entry, LockOptions lockOptions, EventSource source) {
LockMode requestedLockMode = lockOptions.getLockMode();
if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
// The user requested a "greater" (i.e. more restrictive) form of
// pessimistic lock
if ( entry.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"attempted to lock a deleted instance",
entry.getId(),
entry.getPersister().getEntityName()
);
}
final EntityPersister persister = entry.getPersister();
if ( log.isTraceEnabled() ) {
log.tracev(
"Locking {0} in mode: {1}",
MessageHelper.infoString( persister, entry.getId(), source.getFactory() ),
requestedLockMode
);
}
final boolean cachingEnabled = persister.canWriteToCache();
SoftLock lock = null;
Object ck = null;
try {
if ( cachingEnabled ) {
EntityDataAccess cache = persister.getCacheAccessStrategy();
ck = cache.generateCacheKey( entry.getId(), persister, source.getFactory(), source.getTenantIdentifier() );
lock = cache.lockItem( source, ck, entry.getVersion() );
}
if ( persister.isVersioned() && requestedLockMode == LockMode.FORCE ) {
// todo : should we check the current isolation mode explicitly?
Object nextVersion = persister.forceVersionIncrement(
entry.getId(), entry.getVersion(), source
);
entry.forceLocked( object, nextVersion );
}
else {
persister.lock( entry.getId(), entry.getVersion(), object, lockOptions, source );
}
entry.setLockMode(requestedLockMode);
}
finally {
// the database now holds a lock + the object is flushed from the cache,
// so release the soft lock
if ( cachingEnabled ) {
persister.getCacheAccessStrategy().unlockItem( source, ck, lock );
}
}
}
}
/**
* Handle the given create event.
*
* @param event The create event to be handled.
*
*/
public void onPersist(PersistEvent event, Map createCache) throws HibernateException {
final SessionImplementor source = event.getSession();
final Object object = event.getObject();
final Object entity;
if ( object instanceof HibernateProxy ) {
LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
if ( li.isUninitialized() ) {
if ( li.getSession() == source ) {
return; //NOTE EARLY EXIT!
}
else {
throw new PersistentObjectException( "uninitialized proxy passed to persist()" );
}
}
entity = li.getImplementation();
}
else {
entity = object;
}
final String entityName;
if ( event.getEntityName() != null ) {
entityName = event.getEntityName();
}
else {
entityName = source.bestGuessEntityName( entity );
event.setEntityName( entityName );
}
final EntityEntry entityEntry = source.getPersistenceContext().getEntry( entity );
EntityState entityState = getEntityState( entity, entityName, entityEntry, source );
if ( entityState == EntityState.DETACHED ) {
// JPA 2, in its version of a "foreign generated", allows the id attribute value
// to be manually set by the user, even though this manual value is irrelevant.
// The issue is that this causes problems with the Hibernate unsaved-value strategy
// which comes into play here in determining detached/transient state.
//
// Detect if we have this situation and if so null out the id value and calculate the
// entity state again.
// NOTE: entityEntry must be null to get here, so we cannot use any of its values
EntityPersister persister = source.getFactory().getEntityPersister( entityName );
if ( ForeignGenerator.class.isInstance( persister.getIdentifierGenerator() ) ) {
if ( LOG.isDebugEnabled() && persister.getIdentifier( entity, source ) != null ) {
LOG.debug( "Resetting entity id attribute to null for foreign generator" );
}
persister.setIdentifier( entity, null, source );
entityState = getEntityState( entity, entityName, entityEntry, source );
}
}
switch ( entityState ) {
case DETACHED: {
throw new PersistentObjectException(
"detached entity passed to persist: " +
getLoggableName( event.getEntityName(), entity )
);
}
case PERSISTENT: {
entityIsPersistent( event, createCache );
break;
}
case TRANSIENT: {
entityIsTransient( event, createCache );
break;
}
case DELETED: {
entityEntry.setStatus( Status.MANAGED );
entityEntry.setDeletedState( null );
event.getSession().getActionQueue().unScheduleDeletion( entityEntry, event.getObject() );
entityIsDeleted( event, createCache );
break;
}
default: {
throw new ObjectDeletedException(
"deleted entity passed to persist",
null,
getLoggableName( event.getEntityName(), entity )
);
}
}
}
/**
* Handle the given merge event.
*
* @param event The merge event to be handled.
*
* @throws HibernateException
*/
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException {
final MergeContext copyCache = (MergeContext) copiedAlready;
final EventSource source = event.getSession();
final Object original = event.getOriginal();
if ( original != null ) {
final Object entity;
if ( original instanceof HibernateProxy ) {
LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer();
if ( li.isUninitialized() ) {
LOG.trace( "Ignoring uninitialized proxy" );
event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) );
return; //EARLY EXIT!
}
else {
entity = li.getImplementation();
}
}
else {
entity = original;
}
if ( copyCache.containsKey( entity ) &&
( copyCache.isOperatedOn( entity ) ) ) {
LOG.trace( "Already in merge process" );
event.setResult( entity );
}
else {
if ( copyCache.containsKey( entity ) ) {
LOG.trace( "Already in copyCache; setting in merge process" );
copyCache.setOperatedOn( entity, true );
}
event.setEntity( entity );
EntityState entityState = null;
// Check the persistence context for an entry relating to this
// entity to be merged...
EntityEntry entry = source.getPersistenceContext().getEntry( entity );
if ( entry == null ) {
EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
Serializable id = persister.getIdentifier( entity, source );
if ( id != null ) {
final EntityKey key = source.generateEntityKey( id, persister );
final Object managedEntity = source.getPersistenceContext().getEntity( key );
entry = source.getPersistenceContext().getEntry( managedEntity );
if ( entry != null ) {
// we have specialized case of a detached entity from the
// perspective of the merge operation. Specifically, we
// have an incoming entity instance which has a corresponding
// entry in the current persistence context, but registered
// under a different entity instance
entityState = EntityState.DETACHED;
}
}
}
if ( entityState == null ) {
entityState = getEntityState( entity, event.getEntityName(), entry, source );
}
switch ( entityState ) {
case DETACHED:
entityIsDetached( event, copyCache );
break;
case TRANSIENT:
entityIsTransient( event, copyCache );
break;
case PERSISTENT:
entityIsPersistent( event, copyCache );
break;
default: //DELETED
throw new ObjectDeletedException(
"deleted instance passed to merge",
null,
getLoggableName( event.getEntityName(), entity )
);
}
}
}
}
/**
* Performs a pessimistic lock upgrade on a given entity, if needed.
*
* @param object The entity for which to upgrade the lock.
* @param entry The entity's EntityEntry instance.
* @param requestedLockMode The lock mode being requested for locking.
* @param source The session which is the source of the event being processed.
* @throws HibernateException
*/
protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode, SessionImplementor source)
throws HibernateException {
if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
// The user requested a "greater" (i.e. more restrictive) form of
// pessimistic lock
if ( entry.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"attempted to lock a deleted instance",
entry.getId(),
entry.getPersister().getEntityName()
);
}
final EntityPersister persister = entry.getPersister();
if ( log.isTraceEnabled() )
log.trace(
"locking " +
MessageHelper.infoString( persister, entry.getId(), source.getFactory() ) +
" in mode: " +
requestedLockMode
);
final CacheConcurrencyStrategy.SoftLock lock;
final CacheKey ck;
if ( persister.hasCache() ) {
ck = new CacheKey(
entry.getId(),
persister.getIdentifierType(),
persister.getRootEntityName(),
source.getEntityMode(),
source.getFactory()
);
lock = persister.getCache().lock( ck, entry.getVersion() );
}
else {
ck = null;
lock = null;
}
try {
if ( persister.isVersioned() && requestedLockMode == LockMode.FORCE ) {
// todo : should we check the current isolation mode explicitly?
Object nextVersion = persister.forceVersionIncrement(
entry.getId(), entry.getVersion(), source
);
entry.forceLocked( object, nextVersion );
}
else {
persister.lock( entry.getId(), entry.getVersion(), object, requestedLockMode, source );
}
entry.setLockMode(requestedLockMode);
}
finally {
// the database now holds a lock + the object is flushed from the cache,
// so release the soft lock
if ( persister.hasCache() ) {
persister.getCache().release(ck, lock );
}
}
}
}
/**
* Handle the given create event.
*
* @param event The create event to be handled.
* @throws HibernateException
*/
public void onPersist(PersistEvent event, Map createCache) throws HibernateException {
final SessionImplementor source = event.getSession();
final Object object = event.getObject();
final Object entity;
if (object instanceof HibernateProxy) {
LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
if ( li.isUninitialized() ) {
if ( li.getSession()==source ) {
return; //NOTE EARLY EXIT!
}
else {
throw new PersistentObjectException("uninitialized proxy passed to persist()");
}
}
entity = li.getImplementation();
}
else {
entity = object;
}
int entityState = getEntityState(
entity,
event.getEntityName(),
source.getPersistenceContext().getEntry(entity),
source
);
switch (entityState) {
case DETACHED:
throw new PersistentObjectException(
"detached entity passed to persist: " +
getLoggableName( event.getEntityName(), entity )
);
case PERSISTENT:
entityIsPersistent(event, createCache);
break;
case TRANSIENT:
entityIsTransient(event, createCache);
break;
default:
throw new ObjectDeletedException(
"deleted entity passed to persist",
null,
getLoggableName( event.getEntityName(), entity )
);
}
}
/**
* Handle the given merge event.
*
* @param event The merge event to be handled.
* @throws HibernateException
*/
public void onMerge(MergeEvent event, Map copyCache) throws HibernateException {
final EventSource source = event.getSession();
final Object original = event.getOriginal();
if ( original != null ) {
final Object entity;
if ( original instanceof HibernateProxy ) {
LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer();
if ( li.isUninitialized() ) {
log.trace("ignoring uninitialized proxy");
event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) );
return; //EARLY EXIT!
}
else {
entity = li.getImplementation();
}
}
else {
entity = original;
}
if ( copyCache.containsKey(entity) ) {
log.trace("already merged");
event.setResult(entity);
}
else {
event.setEntity( entity );
int entityState = -1;
// Check the persistence context for an entry relating to this
// entity to be merged...
EntityEntry entry = source.getPersistenceContext().getEntry( entity );
if ( entry == null ) {
EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
if ( id != null ) {
EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
Object managedEntity = source.getPersistenceContext().getEntity( key );
entry = source.getPersistenceContext().getEntry( managedEntity );
if ( entry != null ) {
// we have specialized case of a detached entity from the
// perspective of the merge operation. Specifically, we
// have an incoming entity instance which has a corresponding
// entry in the current persistence context, but registered
// under a different entity instance
entityState = DETACHED;
}
}
}
if ( entityState == -1 ) {
entityState = getEntityState( entity, event.getEntityName(), entry, source );
}
switch (entityState) {
case DETACHED:
entityIsDetached(event, copyCache);
break;
case TRANSIENT:
entityIsTransient(event, copyCache);
break;
case PERSISTENT:
entityIsPersistent(event, copyCache);
break;
default: //DELETED
throw new ObjectDeletedException(
"deleted instance passed to merge",
null,
getLoggableName( event.getEntityName(), entity )
);
}
}
}
}