HHH-7377 - NullPointerException in conjunction with natural IDs after Session.clear()

(cherry picked from commit 785e2d869e)
This commit is contained in:
Steve Ebersole 2012-11-08 09:59:13 -06:00
parent 502542d2b6
commit e5f0db2455
5 changed files with 91 additions and 5 deletions

View File

@ -2092,6 +2092,15 @@ public class StatefulPersistenceContext implements PersistenceContext {
public void cleanupFromSynchronizations() {
naturalIdXrefDelegate.unStashInvalidNaturalIdReferences();
}
@Override
public void handleEviction(Object object, EntityPersister persister, Serializable identifier) {
naturalIdXrefDelegate.removeNaturalIdCrossReference(
persister,
identifier,
findCachedNaturalId( persister, identifier )
);
}
};
@Override

View File

@ -830,6 +830,15 @@ public interface PersistenceContext {
* of old values as no longer valid.
*/
public void cleanupFromSynchronizations();
/**
* Called on {@link org.hibernate.Session#evict} to give a chance to clean up natural-id cross refs.
*
* @param object The entity instance.
* @param persister The entity persister
* @param identifier The entity identifier
*/
public void handleEviction(Object object, EntityPersister persister, Serializable identifier);
}
/**

View File

@ -80,7 +80,7 @@ public class DefaultEvictEventListener implements EvictEventListener {
if ( !li.isUninitialized() ) {
final Object entity = persistenceContext.removeEntity( key );
if ( entity != null ) {
EntityEntry e = event.getSession().getPersistenceContext().removeEntry( entity );
EntityEntry e = persistenceContext.removeEntry( entity );
doEvict( entity, key, e.getPersister(), event.getSession() );
}
}
@ -106,6 +106,10 @@ public class DefaultEvictEventListener implements EvictEventListener {
LOG.tracev( "Evicting {0}", MessageHelper.infoString( persister ) );
}
if ( persister.hasNaturalIdentifier() ) {
session.getPersistenceContext().getNaturalIdHelper().handleEviction( object, persister, key.getIdentifier() );
}
// remove all collections for the entity from the session-level cache
if ( persister.hasCollections() ) {
new EvictVisitor( session ).process( object, persister );

View File

@ -2491,12 +2491,12 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
// synchronization (this process) was disabled
return;
}
if ( ! isTransactionInProgress() ) {
// not in a transaction so skip synchronization
if ( entityPersister.getEntityMetamodel().hasImmutableNaturalId() ) {
// only mutable natural-ids need this processing
return;
}
if ( entityPersister.getEntityMetamodel().hasImmutableNaturalId() ) {
// only mutable natural-ids need this processing
if ( ! isTransactionInProgress() ) {
// not in a transaction so skip synchronization
return;
}
@ -2505,6 +2505,16 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
final Object entity = getPersistenceContext().getEntity( entityKey );
final EntityEntry entry = getPersistenceContext().getEntry( entity );
if ( entry == null ) {
if ( LOG.isDebugEnabled() ) {
LOG.debug(
"Cached natural-id/pk resolution linked to null EntityEntry in persistence context : "
+ MessageHelper.infoString( entityPersister, pk, getFactory() )
);
}
continue;
}
if ( !entry.requiresDirtyCheck( entity ) ) {
continue;
}

View File

@ -472,4 +472,58 @@ public class MutableNaturalIdTest extends BaseCoreFunctionalTestCase {
t.commit();
s.close();
}
@Test
public void testClear() {
Session s = openSession();
s.beginTransaction();
User u = new User( "steve", "hb", "superSecret" );
s.persist( u );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
u = (User) session.byNaturalId( User.class )
.using( "name", "steve" )
.using( "org", "hb" )
.load();
assertNotNull( u );
s.clear();
u = (User) session.byNaturalId( User.class )
.using( "name", "steve" )
.using( "org", "hb" )
.load();
assertNotNull( u );
s.delete( u );
s.getTransaction().commit();
s.close();
}
@Test
public void testEviction() {
Session s = openSession();
s.beginTransaction();
User u = new User( "steve", "hb", "superSecret" );
s.persist( u );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
u = (User) session.byNaturalId( User.class )
.using( "name", "steve" )
.using( "org", "hb" )
.load();
assertNotNull( u );
s.evict( u );
u = (User) session.byNaturalId( User.class )
.using( "name", "steve" )
.using( "org", "hb" )
.load();
assertNotNull( u );
s.delete( u );
s.getTransaction().commit();
s.close();
}
}