introduce Contexts for the other cascading operations that need them

and typesafety, finally!
This commit is contained in:
Gavin King 2022-01-30 14:06:26 +01:00
parent 7570d15291
commit 1b0862babd
27 changed files with 381 additions and 233 deletions

View File

@ -8,7 +8,6 @@ package org.hibernate.engine.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -21,6 +20,7 @@ import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
@ -56,8 +56,8 @@ public final class Cascade {
* @param persister The parent's entity persister
* @param parent The parent reference.
*/
public static void cascade(
final CascadingAction action, final CascadePoint cascadePoint,
public static <T> void cascade(
final CascadingAction<T> action, final CascadePoint cascadePoint,
final EventSource eventSource, final EntityPersister persister, final Object parent)
throws HibernateException {
cascade( action, cascadePoint, eventSource, persister, parent, null );
@ -72,13 +72,13 @@ public final class Cascade {
* @param anything Anything ;) Typically some form of cascade-local cache
* which is specific to each CascadingAction type
*/
public static void cascade(
final CascadingAction action,
public static <T> void cascade(
final CascadingAction<T> action,
final CascadePoint cascadePoint,
final EventSource eventSource,
final EntityPersister persister,
final Object parent,
final Object anything) throws HibernateException {
final T anything) throws HibernateException {
if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt
final boolean traceEnabled = LOG.isTraceEnabled();
@ -106,7 +106,7 @@ public final class Cascade {
// Cascade to an uninitialized, lazy value only if
// parent is managed in the PersistenceContext.
// If parent is a detached entity being merged,
// then parent will not be in the PersistencContext
// then parent will not be in the PersistenceContext
// (so lazy attributes must not be initialized).
if ( persistenceContext.getEntry( parent ) == null ) {
// parent was not in the PersistenceContext
@ -199,8 +199,8 @@ public final class Cascade {
/**
* Cascade an action to the child or children
*/
private static void cascadeProperty(
final CascadingAction action,
private static <T> void cascadeProperty(
final CascadingAction<T> action,
final CascadePoint cascadePoint,
final EventSource eventSource,
List<String> componentPath,
@ -209,7 +209,7 @@ public final class Cascade {
final Type type,
final CascadeStyle style,
final String propertyName,
final Object anything,
final T anything,
final boolean isCascadeDeleteEnabled) throws HibernateException {
if ( child != null ) {
@ -265,8 +265,8 @@ public final class Cascade {
isCascadeDeleteEnabled );
}
private static void cascadeLogicalOneToOneOrphanRemoval(
final CascadingAction action,
private static <T> void cascadeLogicalOneToOneOrphanRemoval(
final CascadingAction<T> action,
final EventSource eventSource,
final List<String> componentPath,
final Object parent,
@ -355,7 +355,7 @@ public final class Cascade {
}
else {
// Else, we must delete after the updates.
eventSource.delete( entityName, loadedValue, isCascadeDeleteEnabled, new HashSet<>() );
eventSource.delete( entityName, loadedValue, isCascadeDeleteEnabled, DeleteContext.create() );
}
}
}
@ -380,15 +380,15 @@ public final class Cascade {
return associationType.getForeignKeyDirection().cascadeNow( cascadePoint );
}
private static void cascadeComponent(
final CascadingAction action,
private static <T> void cascadeComponent(
final CascadingAction<T> action,
final CascadePoint cascadePoint,
final EventSource eventSource,
final List<String> componentPath,
final Object parent,
final Object child,
final CompositeType componentType,
final Object anything) {
final T anything) {
Object[] children = null;
final Type[] types = componentType.getSubtypes();
@ -418,8 +418,8 @@ public final class Cascade {
}
}
private static void cascadeAssociation(
final CascadingAction action,
private static <T> void cascadeAssociation(
final CascadingAction<T> action,
final CascadePoint cascadePoint,
final EventSource eventSource,
final List<String> componentPath,
@ -427,7 +427,7 @@ public final class Cascade {
final Object child,
final Type type,
final CascadeStyle style,
final Object anything,
final T anything,
final boolean isCascadeDeleteEnabled) {
if ( type.isEntityType() || type.isAnyType() ) {
cascadeToOne( action, eventSource, parent, child, type, style, anything, isCascadeDeleteEnabled );
@ -450,15 +450,15 @@ public final class Cascade {
/**
* Cascade an action to a collection
*/
private static void cascadeCollection(
final CascadingAction action,
private static <T> void cascadeCollection(
final CascadingAction<T> action,
final CascadePoint cascadePoint,
final EventSource eventSource,
final List<String> componentPath,
final Object parent,
final Object child,
final CascadeStyle style,
final Object anything,
final T anything,
final CollectionType type) {
final CollectionPersister persister = eventSource.getFactory()
.getRuntimeMetamodels()
@ -492,14 +492,14 @@ public final class Cascade {
/**
* Cascade an action to a to-one association or any type
*/
private static void cascadeToOne(
final CascadingAction action,
private static <T> void cascadeToOne(
final CascadingAction<T> action,
final EventSource eventSource,
final Object parent,
final Object child,
final Type type,
final CascadeStyle style,
final Object anything,
final T anything,
final boolean isCascadeDeleteEnabled) {
final String entityName = type.isEntityType()
? ( (EntityType) type ).getAssociatedEntityName()
@ -520,8 +520,8 @@ public final class Cascade {
/**
* Cascade to the collection elements
*/
private static void cascadeCollectionElements(
final CascadingAction action,
private static <T> void cascadeCollectionElements(
final CascadingAction<T> action,
final CascadePoint cascadePoint,
final EventSource eventSource,
final List<String> componentPath,
@ -530,9 +530,10 @@ public final class Cascade {
final CollectionType collectionType,
final CascadeStyle style,
final Type elemType,
final Object anything,
final T anything,
final boolean isCascadeDeleteEnabled) throws HibernateException {
final boolean reallyDoCascade = style.reallyDoCascade( action ) && child != CollectionType.UNFETCHED_COLLECTION;
final boolean reallyDoCascade = style.reallyDoCascade( action )
&& child != CollectionType.UNFETCHED_COLLECTION;
if ( reallyDoCascade ) {
final boolean traceEnabled = LOG.isTraceEnabled();
@ -605,7 +606,7 @@ public final class Cascade {
for ( Object orphan : orphans ) {
if ( orphan != null ) {
LOG.tracev( "Deleting orphaned entity instance: {0}", entityName );
eventSource.delete( entityName, orphan, false, new HashSet<>() );
eventSource.delete( entityName, orphan, false, DeleteContext.create() );
}
}
}

View File

@ -20,7 +20,7 @@ import org.hibernate.type.Type;
* @author Gavin King
* @author Steve Ebersole
*/
public interface CascadingAction {
public interface CascadingAction<T> {
/**
* Cascade the action to the child object.
@ -36,7 +36,7 @@ public interface CascadingAction {
EventSource session,
Object child,
String entityName,
Object anything,
T anything,
boolean isCascadeDeleteEnabled) throws HibernateException;
/**

View File

@ -7,8 +7,6 @@
package org.hibernate.engine.spi;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
@ -17,8 +15,11 @@ import org.hibernate.ReplicationMode;
import org.hibernate.TransientPropertyValueException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.MergeContext;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
@ -46,16 +47,16 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#delete(Object)
*/
public static final CascadingAction DELETE = new BaseCascadingAction() {
public static final CascadingAction<DeleteContext> DELETE = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
DeleteContext context,
boolean isCascadeDeleteEnabled) {
LOG.tracev( "Cascading to delete: {0}", entityName );
session.delete( entityName, child, isCascadeDeleteEnabled, (Set<?>) anything );
session.delete( entityName, child, isCascadeDeleteEnabled, context );
}
@Override
@ -82,19 +83,18 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#lock(Object, LockMode)
*/
public static final CascadingAction LOCK = new BaseCascadingAction() {
public static final CascadingAction<LockOptions> LOCK = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
LockOptions lockOptions,
boolean isCascadeDeleteEnabled) {
LOG.tracev( "Cascading to lock: {0}", entityName );
LockMode lockMode = LockMode.NONE;
LockOptions lr = new LockOptions();
if ( anything instanceof LockOptions ) {
LockOptions lockOptions = (LockOptions) anything;
if ( lockOptions != null ) {
lr.setTimeOut( lockOptions.getTimeOut() );
lr.setScope( lockOptions.getScope() );
lr.setFollowOnLocking( lockOptions.getFollowOnLocking() );
@ -130,17 +130,17 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#refresh(Object)
*/
public static final CascadingAction REFRESH = new BaseCascadingAction() {
public static final CascadingAction<RefreshContext> REFRESH = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
RefreshContext context,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to refresh: {0}", entityName );
session.refresh( entityName, child, (Map<?,?>) anything );
session.refresh( entityName, child, context );
}
@Override
@ -166,13 +166,13 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#evict(Object)
*/
public static final CascadingAction EVICT = new BaseCascadingAction() {
public static final CascadingAction<Void> EVICT = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
Void nothing,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to evict: {0}", entityName );
@ -207,13 +207,13 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#saveOrUpdate(Object)
*/
public static final CascadingAction SAVE_UPDATE = new BaseCascadingAction() {
public static final CascadingAction<PersistContext> SAVE_UPDATE = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
PersistContext nothing,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to save or update: {0}", entityName );
@ -249,17 +249,17 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#merge(Object)
*/
public static final CascadingAction MERGE = new BaseCascadingAction() {
public static final CascadingAction<MergeContext> MERGE = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
MergeContext context,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to merge: {0}", entityName );
session.merge( entityName, child, (MergeContext) anything );
session.merge( entityName, child, context );
}
@Override
@ -286,17 +286,17 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#persist(Object)
*/
public static final CascadingAction PERSIST = new BaseCascadingAction() {
public static final CascadingAction<PersistContext> PERSIST = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
PersistContext context,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to persist: {0}", entityName );
session.persist( entityName, child, (Map<?,?>) anything );
session.persist( entityName, child, context );
}
@Override
@ -329,17 +329,17 @@ public class CascadingActions {
*
* @see org.hibernate.Session#persist(Object)
*/
public static final CascadingAction PERSIST_ON_FLUSH = new BaseCascadingAction() {
public static final CascadingAction<PersistContext> PERSIST_ON_FLUSH = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
PersistContext anything,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to persist on flush: {0}", entityName );
session.persistOnFlush( entityName, child, (Map<?,?>) anything );
session.persistOnFlush( entityName, child, anything );
}
@Override
@ -373,8 +373,9 @@ public class CascadingActions {
if ( child != null
&& !isInManagedState( child, session )
&& !(child instanceof HibernateProxy) ) { //a proxy cannot be transient and it breaks ForeignKeys.isTransient
final String childEntityName = ((EntityType) propertyType).getAssociatedEntityName(session.getFactory());
if (ForeignKeys.isTransient(childEntityName, child, null, session)) {
final String childEntityName =
((EntityType) propertyType).getAssociatedEntityName( session.getFactory() );
if ( ForeignKeys.isTransient(childEntityName, child, null, session) ) {
String parentEntityName = persister.getEntityName();
String propertyName = persister.getPropertyNames()[propertyIndex];
throw new TransientPropertyValueException(
@ -412,17 +413,17 @@ public class CascadingActions {
/**
* @see org.hibernate.Session#replicate
*/
public static final CascadingAction REPLICATE = new BaseCascadingAction() {
public static final CascadingAction<ReplicationMode> REPLICATE = new BaseCascadingAction<>() {
@Override
public void cascade(
EventSource session,
Object child,
String entityName,
Object anything,
ReplicationMode anything,
boolean isCascadeDeleteEnabled)
throws HibernateException {
LOG.tracev( "Cascading to replicate: {0}", entityName );
session.replicate( entityName, child, (ReplicationMode) anything );
session.replicate( entityName, child, anything );
}
@Override
@ -445,7 +446,7 @@ public class CascadingActions {
}
};
public abstract static class BaseCascadingAction implements CascadingAction {
public abstract static class BaseCascadingAction<T> implements CascadingAction<T> {
@Override
public boolean requiresNoCascadeChecking() {
return false;

View File

@ -37,7 +37,10 @@ import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.MergeContext;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
@ -1102,22 +1105,22 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
@Override
public void persist(String entityName, Object object, Map createdAlready) throws HibernateException {
public void persist(String entityName, Object object, PersistContext createdAlready) throws HibernateException {
delegate.persist( entityName, object, createdAlready );
}
@Override
public void persistOnFlush(String entityName, Object object, Map copiedAlready) {
public void persistOnFlush(String entityName, Object object, PersistContext copiedAlready) {
delegate.persistOnFlush( entityName, object, copiedAlready );
}
@Override
public void refresh(String entityName, Object object, Map refreshedAlready) throws HibernateException {
public void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException {
delegate.refresh( entityName, object, refreshedAlready );
}
@Override
public void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, Set transientEntities) {
public void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, DeleteContext transientEntities) {
delegate.delete( entityName, child, isCascadeDeleteEnabled, transientEntities );
}

View File

@ -11,7 +11,10 @@ import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.MergeContext;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
@ -84,25 +87,25 @@ public interface SessionImplementor extends Session, SharedSessionContractImplem
* @deprecated OperationalContext should cover this overload I believe
*/
@Deprecated
void persist(String entityName, Object object, Map createdAlready) throws HibernateException;
void persist(String entityName, Object object, PersistContext createdAlready) throws HibernateException;
/**
* @deprecated OperationalContext should cover this overload I believe
*/
@Deprecated
void persistOnFlush(String entityName, Object object, Map copiedAlready);
void persistOnFlush(String entityName, Object object, PersistContext copiedAlready);
/**
* @deprecated OperationalContext should cover this overload I believe
*/
@Deprecated
void refresh(String entityName, Object object, Map refreshedAlready) throws HibernateException;
void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException;
/**
* @deprecated OperationalContext should cover this overload I believe
*/
@Deprecated
void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, Set transientEntities);
void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, DeleteContext transientEntities);
/**
* @deprecated OperationalContext should cover this overload I believe

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.event.internal;
import java.util.IdentityHashMap;
import java.util.Map;
import org.hibernate.HibernateException;
@ -33,6 +32,7 @@ import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.FlushEntityEvent;
import org.hibernate.event.spi.FlushEntityEventListener;
import org.hibernate.event.spi.FlushEvent;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.EntityPrinter;
import org.hibernate.persister.entity.EntityPersister;
@ -135,19 +135,19 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
LOG.debug( "Processing flush-time cascades" );
final Object anything = getAnything();
final PersistContext context = getContext();
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
for ( Map.Entry<Object,EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
// for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
EntityEntry entry = me.getValue();
Status status = entry.getStatus();
if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
cascadeOnFlush( session, entry.getPersister(), me.getKey(), anything );
cascadeOnFlush( session, entry.getPersister(), me.getKey(), context );
}
}
}
private void cascadeOnFlush(EventSource session, EntityPersister persister, Object object, Object anything)
private void cascadeOnFlush(EventSource session, EntityPersister persister, Object object, PersistContext anything)
throws HibernateException {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
persistenceContext.incrementCascadeLevel();
@ -159,11 +159,11 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
}
}
protected Object getAnything() {
return jpaBootstrap ? new IdentityHashMap<>(10) : null;
protected PersistContext getContext() {
return jpaBootstrap ? PersistContext.create() : null;
}
protected CascadingAction getCascadingAction() {
protected CascadingAction<PersistContext> getCascadingAction() {
return jpaBootstrap ? CascadingActions.PERSIST_ON_FLUSH : CascadingActions.SAVE_UPDATE;
}
@ -177,9 +177,7 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
// and reset reached, doupdate, etc.
LOG.debug( "Dirty checking collections" );
persistenceContext.forEachCollectionEntry( (pc,ce) -> {
ce.preFlush( pc );
}, true );
persistenceContext.forEachCollectionEntry( (pc,ce) -> ce.preFlush( pc ), true );
}
/**

View File

@ -42,7 +42,7 @@ import org.hibernate.type.TypeHelper;
*
* @author Steve Ebersole.
*/
public abstract class AbstractSaveEventListener
public abstract class AbstractSaveEventListener<C>
extends AbstractReassociateEventListener
implements CallbackRegistryConsumer {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractSaveEventListener.class );
@ -59,7 +59,7 @@ public abstract class AbstractSaveEventListener
* @param entity The entity to be saved.
* @param requestedId The id to which to associate the entity.
* @param entityName The name of the entity being saved.
* @param anything Generally cascade-specific information.
* @param context Generally cascade-specific information.
* @param source The session which is the source of this save event.
*
* @return The id used to save the entity.
@ -68,7 +68,7 @@ public abstract class AbstractSaveEventListener
Object entity,
Object requestedId,
String entityName,
Object anything,
C context,
EventSource source) {
callbackRegistry.preCreate( entity );
@ -77,7 +77,7 @@ public abstract class AbstractSaveEventListener
requestedId,
source.getEntityPersister( entityName, entity ),
false,
anything,
context,
source,
true
);
@ -88,7 +88,7 @@ public abstract class AbstractSaveEventListener
*
* @param entity The entity to be saved
* @param entityName The entity-name for the entity to be saved
* @param anything Generally cascade-specific information.
* @param context Generally cascade-specific information.
* @param source The session which is the source of this save event.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
@ -101,7 +101,7 @@ public abstract class AbstractSaveEventListener
protected Object saveWithGeneratedId(
Object entity,
String entityName,
Object anything,
C context,
EventSource source,
boolean requiresImmediateIdAccess) {
callbackRegistry.preCreate( entity );
@ -119,7 +119,7 @@ public abstract class AbstractSaveEventListener
return source.getIdentifier( entity );
}
else if ( generatedId == IdentifierGeneratorHelper.POST_INSERT_INDICATOR ) {
return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
return performSave( entity, null, persister, true, context, source, requiresImmediateIdAccess );
}
else {
// TODO: define toString()s for generators
@ -131,7 +131,7 @@ public abstract class AbstractSaveEventListener
);
}
return performSave( entity, generatedId, persister, false, anything, source, true );
return performSave( entity, generatedId, persister, false, context, source, true );
}
}
@ -143,7 +143,7 @@ public abstract class AbstractSaveEventListener
* @param id The id by which to save the entity.
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column being used?
* @param anything Generally cascade-specific information.
* @param context Generally cascade-specific information.
* @param source The session from which the event originated.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
@ -158,7 +158,7 @@ public abstract class AbstractSaveEventListener
Object id,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
C context,
EventSource source,
boolean requiresImmediateIdAccess) {
@ -194,7 +194,7 @@ public abstract class AbstractSaveEventListener
key,
persister,
useIdentityColumn,
anything,
context,
source,
requiresImmediateIdAccess
);
@ -221,7 +221,7 @@ public abstract class AbstractSaveEventListener
* @param key The id to be used for saving the entity (or null, in the case of identity columns)
* @param persister The entity's persister instance.
* @param useIdentityColumn Should an identity column be used for id generation?
* @param anything Generally cascade-specific information.
* @param context Generally cascade-specific information.
* @param source The session which is the source of the current event.
* @param requiresImmediateIdAccess Is access to the identifier required immediately
* after the completion of the save? persist(), for example, does not require this...
@ -234,7 +234,7 @@ public abstract class AbstractSaveEventListener
EntityKey key,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
C context,
EventSource source,
boolean requiresImmediateIdAccess) {
@ -260,9 +260,9 @@ public abstract class AbstractSaveEventListener
false
);
cascadeBeforeSave( source, persister, entity, anything );
cascadeBeforeSave( source, persister, entity, context );
Object[] values = persister.getPropertyValuesToInsert( entity, getMergeMap( anything ), source );
Object[] values = persister.getPropertyValuesToInsert( entity, getMergeMap( context ), source );
Type[] types = persister.getPropertyTypes();
boolean substitute = substituteValuesIfNecessary( entity, id, values, persister, source );
@ -295,7 +295,7 @@ public abstract class AbstractSaveEventListener
// postpone initializing id in case the insert has non-nullable transient dependencies
// that are not resolved until cascadeAfterSave() is executed
cascadeAfterSave( source, persister, entity, anything );
cascadeAfterSave( source, persister, entity, context );
if ( useIdentityColumn && insert.isEarlyInsert() ) {
if ( !(insert instanceof EntityIdentityInsertAction) ) {
throw new IllegalStateException(
@ -355,7 +355,7 @@ public abstract class AbstractSaveEventListener
}
}
protected Map<Object,Object> getMergeMap(Object anything) {
protected Map<Object,Object> getMergeMap(C anything) {
return null;
}
@ -427,13 +427,13 @@ public abstract class AbstractSaveEventListener
* @param source The session from which the save event originated.
* @param persister The entity's persister instance.
* @param entity The entity to be saved.
* @param anything Generally cascade-specific data
* @param context Generally cascade-specific data
*/
protected void cascadeBeforeSave(
EventSource source,
EntityPersister persister,
Object entity,
Object anything) {
C context) {
// cascade-save to many-to-one BEFORE the parent is saved
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
@ -445,7 +445,7 @@ public abstract class AbstractSaveEventListener
source,
persister,
entity,
anything
context
);
}
finally {
@ -459,13 +459,13 @@ public abstract class AbstractSaveEventListener
* @param source The session from which the event originated.
* @param persister The entity's persister instance.
* @param entity The entity being saved.
* @param anything Generally cascade-specific data
* @param context Generally cascade-specific data
*/
protected void cascadeAfterSave(
EventSource source,
EntityPersister persister,
Object entity,
Object anything) {
C context) {
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
// cascade-save to collections AFTER the collection owner was saved
@ -477,7 +477,7 @@ public abstract class AbstractSaveEventListener
source,
persister,
entity,
anything
context
);
}
finally {
@ -485,6 +485,6 @@ public abstract class AbstractSaveEventListener
}
}
protected abstract CascadingAction getCascadeAction();
protected abstract CascadingAction<C> getCascadeAction();
}

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.event.internal;
import java.util.Set;
import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
@ -26,12 +24,12 @@ import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.service.spi.JpaBootstrapSensitive;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
import org.hibernate.persister.entity.EntityPersister;
@ -68,7 +66,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
*
*/
public void onDelete(DeleteEvent event) throws HibernateException {
onDelete( event, new IdentitySet<>() );
onDelete( event, DeleteContext.create() );
}
/**
@ -78,7 +76,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
* @param transientEntities The cache of entities already deleted
*
*/
public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {
public void onDelete(DeleteEvent event, DeleteContext transientEntities) throws HibernateException {
final EventSource source = event.getSession();
@ -208,13 +206,12 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
Object entity,
boolean cascadeDeleteEnabled,
EntityPersister persister,
Set transientEntities) {
DeleteContext transientEntities) {
LOG.handlingTransientEntity();
if ( transientEntities.contains( entity ) ) {
if ( !transientEntities.add( entity ) ) {
LOG.trace( "Already handled transient entity; skipping" );
return;
}
transientEntities.add( entity );
cascadeBeforeDelete( session, persister, entity, null, transientEntities );
cascadeAfterDelete( session, persister, entity, transientEntities );
}
@ -238,7 +235,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
final boolean isCascadeDeleteEnabled,
final boolean isOrphanRemovalBeforeUpdates,
final EntityPersister persister,
final Set transientEntities) {
final DeleteContext transientEntities) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
@ -342,7 +339,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
EntityPersister persister,
Object entity,
EntityEntry entityEntry,
Set transientEntities) throws HibernateException {
DeleteContext transientEntities) throws HibernateException {
CacheMode cacheMode = session.getCacheMode();
session.setCacheMode( CacheMode.GET );
@ -369,7 +366,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
EventSource session,
EntityPersister persister,
Object entity,
Set transientEntities) throws HibernateException {
DeleteContext transientEntities) throws HibernateException {
CacheMode cacheMode = session.getCacheMode();
session.setCacheMode( CacheMode.GET );

View File

@ -48,12 +48,14 @@ import org.hibernate.type.TypeHelper;
*
* @author Gavin King
*/
public class DefaultMergeEventListener extends AbstractSaveEventListener implements MergeEventListener {
public class DefaultMergeEventListener
extends AbstractSaveEventListener<MergeContext>
implements MergeEventListener {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultMergeEventListener.class );
@Override
protected Map<Object,Object> getMergeMap(Object anything) {
return ( (MergeContext) anything ).invertMap();
protected Map<Object,Object> getMergeMap(MergeContext context) {
return context.invertMap();
}
/**
@ -126,14 +128,14 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
entity = original;
}
if ( ((MergeContext) copiedAlready).containsKey( entity ) && ((MergeContext) copiedAlready).isOperatedOn( entity ) ) {
if ( copiedAlready.containsKey( entity ) && copiedAlready.isOperatedOn( entity ) ) {
LOG.trace( "Already in merge process" );
event.setResult( entity );
}
else {
if ( ((MergeContext) copiedAlready).containsKey( entity ) ) {
if ( copiedAlready.containsKey( entity ) ) {
LOG.trace( "Already in copyCache; setting in merge process" );
((MergeContext) copiedAlready).setOperatedOn( entity, true );
copiedAlready.setOperatedOn( entity, true );
}
event.setEntity( entity );
EntityState entityState = null;
@ -166,13 +168,13 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
switch ( entityState ) {
case DETACHED:
entityIsDetached( event, (MergeContext) copiedAlready);
entityIsDetached( event, copiedAlready);
break;
case TRANSIENT:
entityIsTransient( event, (MergeContext) copiedAlready);
entityIsTransient( event, copiedAlready);
break;
case PERSISTENT:
entityIsPersistent( event, (MergeContext) copiedAlready);
entityIsPersistent( event, copiedAlready);
break;
default: //DELETED
throw new ObjectDeletedException(
@ -530,7 +532,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
@Override
protected CascadingAction getCascadeAction() {
protected CascadingAction<MergeContext> getCascadeAction() {
return CascadingActions.MERGE;
}
@ -538,7 +540,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
* Cascade behavior is redefined by this subclass, disable superclass behavior
*/
@Override
protected void cascadeAfterSave(EventSource source, EntityPersister persister, Object entity, Object anything)
protected void cascadeAfterSave(EventSource source, EntityPersister persister, Object entity, MergeContext anything)
throws HibernateException {
}
@ -546,7 +548,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
* Cascade behavior is redefined by this subclass, disable superclass behavior
*/
@Override
protected void cascadeBeforeSave(EventSource source, EntityPersister persister, Object entity, Object anything)
protected void cascadeBeforeSave(EventSource source, EntityPersister persister, Object entity, MergeContext anything)
throws HibernateException {
}
}

View File

@ -6,9 +6,6 @@
*/
package org.hibernate.event.internal;
import java.util.IdentityHashMap;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.PersistentObjectException;
@ -18,6 +15,7 @@ import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.PersistEvent;
import org.hibernate.event.spi.PersistEventListener;
import org.hibernate.id.ForeignGenerator;
@ -36,12 +34,12 @@ import org.hibernate.proxy.LazyInitializer;
* @author Gavin King
*/
public class DefaultPersistEventListener
extends AbstractSaveEventListener
extends AbstractSaveEventListener<PersistContext>
implements PersistEventListener, CallbackRegistryConsumer {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultPersistEventListener.class );
@Override
protected CascadingAction getCascadeAction() {
protected CascadingAction<PersistContext> getCascadeAction() {
return CascadingActions.PERSIST;
}
@ -52,7 +50,7 @@ public class DefaultPersistEventListener
*
*/
public void onPersist(PersistEvent event) throws HibernateException {
onPersist( event, new IdentityHashMap<>( 10 ) );
onPersist( event, PersistContext.create() );
}
/**
@ -61,7 +59,7 @@ public class DefaultPersistEventListener
* @param event The create event to be handled.
*
*/
public void onPersist(PersistEvent event, Map createCache) throws HibernateException {
public void onPersist(PersistEvent event, PersistContext createCache) throws HibernateException {
final SessionImplementor source = event.getSession();
final Object object = event.getObject();
@ -149,7 +147,7 @@ public class DefaultPersistEventListener
}
protected void entityIsPersistent(PersistEvent event, Map createCache) {
protected void entityIsPersistent(PersistEvent event, PersistContext createCache) {
LOG.trace( "Ignoring persistent instance" );
final EventSource source = event.getSession();
@ -158,13 +156,13 @@ public class DefaultPersistEventListener
final Object entity = source.getPersistenceContextInternal().unproxy( event.getObject() );
final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
if ( createCache.put( entity, entity ) == null ) {
if ( createCache.add( entity ) ) {
justCascade( createCache, source, entity, persister );
}
}
private void justCascade(Map createCache, EventSource source, Object entity, EntityPersister persister) {
private void justCascade(PersistContext createCache, EventSource source, Object entity, EntityPersister persister) {
//TODO: merge into one method!
cascadeBeforeSave( source, persister, entity, createCache );
cascadeAfterSave( source, persister, entity, createCache );
@ -176,18 +174,18 @@ public class DefaultPersistEventListener
* @param event The save event to be handled.
* @param createCache The copy cache of entity instance to merge/copy instance.
*/
protected void entityIsTransient(PersistEvent event, Map createCache) {
protected void entityIsTransient(PersistEvent event, PersistContext createCache) {
LOG.trace( "Saving transient instance" );
final EventSource source = event.getSession();
final Object entity = source.getPersistenceContextInternal().unproxy( event.getObject() );
if ( createCache.put( entity, entity ) == null ) {
if ( createCache.add( entity ) ) {
saveWithGeneratedId( entity, event.getEntityName(), createCache, source, false );
}
}
private void entityIsDeleted(PersistEvent event, Map createCache) {
private void entityIsDeleted(PersistEvent event, PersistContext createCache) {
final EventSource source = event.getSession();
final Object entity = source.getPersistenceContextInternal().unproxy( event.getObject() );
@ -204,7 +202,7 @@ public class DefaultPersistEventListener
);
}
if ( createCache.put( entity, entity ) == null ) {
if ( createCache.add( entity ) ) {
justCascade( createCache, source, entity, persister );
}
}

View File

@ -8,13 +8,14 @@ package org.hibernate.event.internal;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.event.spi.PersistContext;
/**
* When persist is used as the cascade action, persistOnFlush should be used
* @author Emmanuel Bernard
*/
public class DefaultPersistOnFlushEventListener extends DefaultPersistEventListener {
protected CascadingAction getCascadeAction() {
protected CascadingAction<PersistContext> getCascadeAction() {
return CascadingActions.PERSIST_ON_FLUSH;
}
}

View File

@ -6,9 +6,6 @@
*/
package org.hibernate.event.internal;
import java.util.IdentityHashMap;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
@ -26,6 +23,7 @@ import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.event.spi.RefreshEvent;
import org.hibernate.event.spi.RefreshEventListener;
import org.hibernate.internal.CoreLogging;
@ -49,7 +47,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultRefreshEventListener.class );
public void onRefresh(RefreshEvent event) throws HibernateException {
onRefresh( event, new IdentityHashMap<>( 10 ) );
onRefresh( event, RefreshContext.create() );
}
/**
@ -57,7 +55,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
*
* @param event The refresh event to be handled.
*/
public void onRefresh(RefreshEvent event, Map refreshedAlready) {
public void onRefresh(RefreshEvent event, RefreshContext refreshedAlready) {
final EventSource source = event.getSession();
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
@ -74,7 +72,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
final Object object = persistenceContext.unproxyAndReassociate( event.getObject() );
if ( refreshedAlready.containsKey( object ) ) {
if ( !refreshedAlready.add( object ) ) {
LOG.trace( "Already refreshed" );
return;
}
@ -126,7 +124,6 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
}
// cascade the refresh prior to refreshing this entity
refreshedAlready.put( object, object );
Cascade.cascade(
CascadingActions.REFRESH,
CascadePoint.BEFORE_REFRESH,
@ -224,7 +221,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
if ( result != null ) {
// apply `postRefreshLockMode`, if needed
if ( postRefreshLockMode != null ) {
// if we get here, there was a previous entry and we need to re-set its lock-mode
// if we get here, there was a previous entry, and we need to re-set its lock-mode
// - however, the refresh operation actually creates a new entry, so get it
persistenceContext.getEntry( result ).setLockMode( postRefreshLockMode );
}

View File

@ -34,7 +34,9 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
public class DefaultReplicateEventListener extends AbstractSaveEventListener implements ReplicateEventListener {
public class DefaultReplicateEventListener
extends AbstractSaveEventListener<ReplicationMode>
implements ReplicateEventListener {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultReplicateEventListener.class );
/**
@ -88,15 +90,14 @@ public class DefaultReplicateEventListener extends AbstractSaveEventListener imp
);
}
/// HHH-2378
final Object realOldVersion = persister.isVersioned() ? oldVersion : null;
@SuppressWarnings("unchecked")
final BasicType<Object> versionType = (BasicType<Object>) persister.getVersionType();
final Object realOldVersion = persister.isVersioned() ? oldVersion : null; /// HHH-2378
boolean canReplicate = replicationMode.shouldOverwriteCurrentVersion(
entity,
realOldVersion,
persister.getVersion( entity ),
(BasicType<Object>) persister.getVersionType()
versionType
);
// if can replicate, will result in a SQL UPDATE
@ -215,7 +216,7 @@ public class DefaultReplicateEventListener extends AbstractSaveEventListener imp
}
@Override
protected CascadingAction getCascadeAction() {
protected CascadingAction<ReplicationMode> getCascadeAction() {
return CascadingActions.REPLICATE;
}
}

View File

@ -23,6 +23,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.SaveOrUpdateEvent;
import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.internal.CoreLogging;
@ -38,7 +39,9 @@ import org.hibernate.proxy.HibernateProxy;
* @author Steve Ebersole
* @author Gavin King
*/
public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener implements SaveOrUpdateEventListener {
public class DefaultSaveOrUpdateEventListener
extends AbstractSaveEventListener<PersistContext>
implements SaveOrUpdateEventListener {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultSaveOrUpdateEventListener.class );
/**
@ -363,7 +366,7 @@ public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener
}
@Override
protected CascadingAction getCascadeAction() {
protected CascadingAction<PersistContext> getCascadeAction() {
return CascadingActions.SAVE_UPDATE;
}
}

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.event.spi;
import java.util.IdentityHashMap;
/**
* A {@link DeleteEvent} represents a {@linkplain org.hibernate.Session#delete(Object) delete operation}
* applied to a single entity. A {@code DeleteContext} is propagated across all cascaded delete operations,
* and keeps track of all the entities we've already visited.
*
* @author Gavin King
*/
public interface DeleteContext {
boolean add(Object entity);
static DeleteContext create() {
// use extension to avoid creating
// a useless wrapper object
class Impl extends IdentityHashMap<Object,Object>
implements DeleteContext {
Impl() {
super(10);
}
@Override
public boolean add(Object entity) {
return put(entity,entity)==null;
}
}
return new Impl();
}
}

View File

@ -24,5 +24,5 @@ public interface DeleteEventListener {
*/
void onDelete(DeleteEvent event) throws HibernateException;
void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException;
void onDelete(DeleteEvent event, DeleteContext transientEntities) throws HibernateException;
}

View File

@ -6,9 +6,6 @@
*/
package org.hibernate.event.spi;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.EntityEntry;
@ -43,20 +40,20 @@ public interface EventSource extends SessionImplementor {
/**
* Cascade persist an entity instance
*/
void persist(String entityName, Object object, Map createdAlready) throws HibernateException;
void persist(String entityName, Object object, PersistContext createdAlready) throws HibernateException;
/**
* Cascade persist an entity instance during the flush process
*/
void persistOnFlush(String entityName, Object object, Map copiedAlready);
void persistOnFlush(String entityName, Object object, PersistContext copiedAlready);
/**
* Cascade refresh an entity instance
*/
void refresh(String entityName, Object object, Map refreshedAlready) throws HibernateException;
void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException;
/**
* Cascade delete an entity instance
*/
void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, Set transientEntities);
void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, DeleteContext transientEntities);
/**
* A specialized type of deletion for orphan removal that must occur prior to queued inserts and updates.
*/

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.event.spi;
import java.util.IdentityHashMap;
/**
* A {@link PersistEvent} represents a {@linkplain org.hibernate.Session#persist(Object) persist operation}
* applied to a single entity. A {@code PersistContext} is propagated across all cascaded persist operations,
* and keeps track of all the entities we've already visited.
*
* @author Gavin King
*/
public interface PersistContext {
boolean add(Object entity);
static PersistContext create() {
// use extension to avoid creating
// a useless wrapper object
class Impl extends IdentityHashMap<Object,Object>
implements PersistContext {
Impl() {
super(10);
}
@Override
public boolean add(Object entity) {
return put(entity,entity)==null;
}
}
return new Impl();
}
}

View File

@ -29,6 +29,6 @@ public interface PersistEventListener {
*
* @param event The create event to be handled.
*/
void onPersist(PersistEvent event, Map createdAlready) throws HibernateException;
void onPersist(PersistEvent event, PersistContext createdAlready) throws HibernateException;
}

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.event.spi;
import java.util.IdentityHashMap;
/**
* A {@link RefreshEvent} represents a {@linkplain org.hibernate.Session#refresh(Object) refresh operation}
* applied to a single entity. A {@code RefreshContext} is propagated across all cascaded refresh operations,
* and keeps track of all the entities we've already visited.
*
* @author Gavin King
*/
public interface RefreshContext {
boolean add(Object entity);
static RefreshContext create() {
// use extension to avoid creating
// a useless wrapper object
class Impl extends IdentityHashMap<Object,Object>
implements RefreshContext {
Impl() {
super(10);
}
@Override
public boolean add(Object entity) {
return put(entity,entity)==null;
}
}
return new Impl();
}
}

View File

@ -24,6 +24,6 @@ public interface RefreshEventListener {
*/
void onRefresh(RefreshEvent event) throws HibernateException;
void onRefresh(RefreshEvent event, Map refreshedAlready) throws HibernateException;
void onRefresh(RefreshEvent event, RefreshContext refreshedAlready) throws HibernateException;
}

View File

@ -69,6 +69,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.spi.TransactionObserver;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.MergeContext;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.AutoFlushEventListener;
@ -92,8 +93,10 @@ import org.hibernate.event.spi.LockEvent;
import org.hibernate.event.spi.LockEventListener;
import org.hibernate.event.spi.MergeEvent;
import org.hibernate.event.spi.MergeEventListener;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.PersistEvent;
import org.hibernate.event.spi.PersistEventListener;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.event.spi.RefreshEvent;
import org.hibernate.event.spi.RefreshEventListener;
import org.hibernate.event.spi.ReplicateEvent;
@ -180,7 +183,8 @@ public class SessionImpl
implements SessionImplementor, LoadAccessContext, EventSource {
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( SessionImpl.class );
// Defaults to null which means the properties are the default - as defined in FastSessionServices#defaultSessionProperties
// Defaults to null which means the properties are the default
// as defined in FastSessionServices#defaultSessionProperties
private Map<String, Object> properties;
private transient ActionQueue actionQueue;
@ -191,7 +195,7 @@ public class SessionImpl
private LockOptions lockOptions;
private boolean autoClear;
private boolean autoClose;
private final boolean autoClose;
private transient LoadEvent loadEvent; //cached LoadEvent instance
@ -210,7 +214,8 @@ public class SessionImpl
if ( options instanceof SharedSessionCreationOptions ) {
final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options;
final ActionQueue.TransactionCompletionProcesses transactionCompletionProcesses = sharedOptions.getTransactionCompletionProcesses();
final ActionQueue.TransactionCompletionProcesses transactionCompletionProcesses
= sharedOptions.getTransactionCompletionProcesses();
if ( sharedOptions.isTransactionCoordinatorShared() && transactionCompletionProcesses != null ) {
actionQueue.setTransactionCompletionProcesses(
transactionCompletionProcesses,
@ -237,13 +242,12 @@ public class SessionImpl
// do not override explicitly set flush mode ( SessionBuilder#flushMode() )
if ( getHibernateFlushMode() == null ) {
final FlushMode initialMode;
if ( this.properties == null ) {
initialMode = fastSessionServices.initialSessionFlushMode;
}
else {
initialMode = ConfigurationHelper.getFlushMode( getSessionProperty( AvailableSettings.FLUSH_MODE ), FlushMode.AUTO );
}
final FlushMode initialMode = this.properties == null
? fastSessionServices.initialSessionFlushMode
: ConfigurationHelper.getFlushMode(
getSessionProperty(AvailableSettings.FLUSH_MODE),
FlushMode.AUTO
);
setHibernateFlushMode( initialMode );
}
@ -264,7 +268,7 @@ public class SessionImpl
}
if ( log.isTraceEnabled() ) {
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), getTimestamp() );
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), getTransactionStartTimestamp() );
}
}
@ -358,7 +362,8 @@ public class SessionImpl
persistenceContext.clear();
actionQueue.clear();
fastSessionServices.eventListenerGroup_CLEAR.fireLazyEventOnEachListener( this::createClearEvent, ClearEventListener::onClear );
fastSessionServices.eventListenerGroup_CLEAR
.fireLazyEventOnEachListener( this::createClearEvent, ClearEventListener::onClear );
}
private ClearEvent createClearEvent() {
@ -390,7 +395,7 @@ public class SessionImpl
// Original hibernate-entitymanager EM#close behavior
checkSessionFactoryOpen();
checkOpenOrWaitingForAutoClose();
if ( fastSessionServices.discardOnClose || !isTransactionInProgress( false ) ) {
if ( fastSessionServices.discardOnClose || !isTransactionInProgressAndNotMarkedForRollback() ) {
super.close();
}
else {
@ -408,13 +413,15 @@ public class SessionImpl
}
}
private boolean isTransactionInProgress(boolean isMarkedRollbackConsideredActive) {
private boolean isTransactionInProgressAndNotMarkedForRollback() {
if ( waitingForAutoClose ) {
return getSessionFactory().isOpen() &&
getTransactionCoordinator().isTransactionActive( isMarkedRollbackConsideredActive );
return getSessionFactory().isOpen()
&& getTransactionCoordinator().isTransactionActive( false );
}
else {
return !isClosed()
&& getTransactionCoordinator().isTransactionActive( false );
}
return !isClosed() &&
getTransactionCoordinator().isTransactionActive( isMarkedRollbackConsideredActive );
}
@Override
@ -578,8 +585,9 @@ public class SessionImpl
@Override
public void delayedAfterCompletion() {
if ( getTransactionCoordinator() instanceof JtaTransactionCoordinatorImpl ) {
( (JtaTransactionCoordinatorImpl) getTransactionCoordinator() ).getSynchronizationCallbackCoordinator()
TransactionCoordinator coordinator = getTransactionCoordinator();
if ( coordinator instanceof JtaTransactionCoordinatorImpl ) {
( (JtaTransactionCoordinatorImpl) coordinator).getSynchronizationCallbackCoordinator()
.processAnyDelayedAfterCompletion();
}
}
@ -610,7 +618,8 @@ public class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
fastSessionServices.eventListenerGroup_SAVE_UPDATE.fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate );
fastSessionServices.eventListenerGroup_SAVE_UPDATE
.fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate );
checkNoUnresolvedActionsAfterOperation();
}
@ -630,7 +639,8 @@ public class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
fastSessionServices.eventListenerGroup_SAVE.fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate );
fastSessionServices.eventListenerGroup_SAVE
.fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate );
checkNoUnresolvedActionsAfterOperation();
return event.getResultId();
}
@ -652,7 +662,8 @@ public class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
fastSessionServices.eventListenerGroup_UPDATE.fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate );
fastSessionServices.eventListenerGroup_UPDATE
.fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate );
checkNoUnresolvedActionsAfterOperation();
}
@ -685,7 +696,8 @@ public class SessionImpl
private void fireLock(LockEvent event) {
checkOpen();
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_LOCK.fireEventOnEachListener( event, LockEventListener::onLock );
fastSessionServices.eventListenerGroup_LOCK
.fireEventOnEachListener( event, LockEventListener::onLock );
delayedAfterCompletion();
}
@ -704,7 +716,7 @@ public class SessionImpl
}
@Override
public void persist(String entityName, Object object, Map copiedAlready) throws HibernateException {
public void persist(String entityName, Object object, PersistContext copiedAlready) throws HibernateException {
checkOpenOrWaitingForAutoClose();
firePersist( copiedAlready, new PersistEvent( entityName, object, this ) );
}
@ -715,7 +727,8 @@ public class SessionImpl
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
fastSessionServices.eventListenerGroup_PERSIST.fireEventOnEachListener( event, PersistEventListener::onPersist );
fastSessionServices.eventListenerGroup_PERSIST
.fireEventOnEachListener( event, PersistEventListener::onPersist );
}
catch (MappingException e) {
originalException = getExceptionConverter().convert( new IllegalArgumentException( e.getMessage() ) );
@ -751,7 +764,7 @@ public class SessionImpl
}
}
private void firePersist(final Map copiedAlready, final PersistEvent event) {
private void firePersist(final PersistContext copiedAlready, final PersistEvent event) {
pulseTransactionCoordinator();
try {
@ -774,11 +787,12 @@ public class SessionImpl
// persistOnFlush() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void persistOnFlush(String entityName, Object object, Map copiedAlready) {
public void persistOnFlush(String entityName, Object object, PersistContext copiedAlready) {
checkOpenOrWaitingForAutoClose();
pulseTransactionCoordinator();
PersistEvent event = new PersistEvent( entityName, object, this );
fastSessionServices.eventListenerGroup_PERSIST_ONFLUSH.fireEventOnEachListener( event, copiedAlready, PersistEventListener::onPersist );
fastSessionServices.eventListenerGroup_PERSIST_ONFLUSH
.fireEventOnEachListener( event, copiedAlready, PersistEventListener::onPersist );
delayedAfterCompletion();
}
@ -806,7 +820,8 @@ public class SessionImpl
try {
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
fastSessionServices.eventListenerGroup_MERGE.fireEventOnEachListener( event, MergeEventListener::onMerge );
fastSessionServices.eventListenerGroup_MERGE
.fireEventOnEachListener( event, MergeEventListener::onMerge );
checkNoUnresolvedActionsAfterOperation();
}
catch ( ObjectDeletedException sse ) {
@ -826,7 +841,8 @@ public class SessionImpl
private void fireMerge(final MergeContext mergeContext, final MergeEvent event) {
try {
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_MERGE.fireEventOnEachListener( event, mergeContext, MergeEventListener::onMerge );
fastSessionServices.eventListenerGroup_MERGE
.fireEventOnEachListener( event, mergeContext, MergeEventListener::onMerge );
}
catch ( ObjectDeletedException sse ) {
throw getExceptionConverter().convert( new IllegalArgumentException( sse ) );
@ -859,7 +875,7 @@ public class SessionImpl
}
@Override
public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, Set transientEntities)
public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, DeleteContext transientEntities)
throws HibernateException {
checkOpenOrWaitingForAutoClose();
final boolean removingOrphanBeforeUpates = persistenceContext.isRemovingOrphanBeforeUpates();
@ -917,7 +933,8 @@ public class SessionImpl
private void fireDelete(final DeleteEvent event) {
try{
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_DELETE.fireEventOnEachListener( event, DeleteEventListener::onDelete );
fastSessionServices.eventListenerGroup_DELETE
.fireEventOnEachListener( event, DeleteEventListener::onDelete );
}
catch ( ObjectDeletedException sse ) {
throw getExceptionConverter().convert( new IllegalArgumentException( sse ) );
@ -934,10 +951,11 @@ public class SessionImpl
}
}
private void fireDelete(final DeleteEvent event, final Set transientEntities) {
private void fireDelete(final DeleteEvent event, final DeleteContext transientEntities) {
try{
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_DELETE.fireEventOnEachListener( event, transientEntities, DeleteEventListener::onDelete );
fastSessionServices.eventListenerGroup_DELETE
.fireEventOnEachListener( event, transientEntities, DeleteEventListener::onDelete );
}
catch ( ObjectDeletedException sse ) {
throw getExceptionConverter().convert( new IllegalArgumentException( sse ) );
@ -1215,13 +1233,15 @@ public class SessionImpl
// it seems they prevent these hot methods from being inlined.
private void fireLoadNoChecks(final LoadEvent event, final LoadType loadType) {
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_LOAD.fireEventOnEachListener( event, loadType, LoadEventListener::onLoad );
fastSessionServices.eventListenerGroup_LOAD
.fireEventOnEachListener( event, loadType, LoadEventListener::onLoad );
}
private void fireResolveNaturalId(final ResolveNaturalIdEvent event) {
checkOpenOrWaitingForAutoClose();
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_RESOLVE_NATURAL_ID.fireEventOnEachListener( event, ResolveNaturalIdEventListener::onResolveNaturalId );
fastSessionServices.eventListenerGroup_RESOLVE_NATURAL_ID
.fireEventOnEachListener( event, ResolveNaturalIdEventListener::onResolveNaturalId );
delayedAfterCompletion();
}
@ -1259,7 +1279,7 @@ public class SessionImpl
}
@Override
public void refresh(String entityName, Object object, Map refreshedAlready) throws HibernateException {
public void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException {
checkOpenOrWaitingForAutoClose();
fireRefresh( refreshedAlready, new RefreshEvent( entityName, object, this ) );
}
@ -1279,7 +1299,8 @@ public class SessionImpl
}
}
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_REFRESH.fireEventOnEachListener( event, RefreshEventListener::onRefresh );
fastSessionServices.eventListenerGroup_REFRESH
.fireEventOnEachListener( event, RefreshEventListener::onRefresh );
}
catch (RuntimeException e) {
if ( !getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) {
@ -1295,10 +1316,11 @@ public class SessionImpl
}
}
private void fireRefresh(final Map refreshedAlready, final RefreshEvent event) {
private void fireRefresh(final RefreshContext refreshedAlready, final RefreshEvent event) {
try {
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_REFRESH.fireEventOnEachListener( event, refreshedAlready, RefreshEventListener::onRefresh );
fastSessionServices.eventListenerGroup_REFRESH
.fireEventOnEachListener( event, refreshedAlready, RefreshEventListener::onRefresh );
}
catch (RuntimeException e) {
throw getExceptionConverter().convert( e );
@ -1325,7 +1347,8 @@ public class SessionImpl
private void fireReplicate(final ReplicateEvent event) {
checkOpen();
pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_REPLICATE.fireEventOnEachListener( event, ReplicateEventListener::onReplicate );
fastSessionServices.eventListenerGroup_REPLICATE
.fireEventOnEachListener( event, ReplicateEventListener::onReplicate );
delayedAfterCompletion();
}
@ -1341,7 +1364,8 @@ public class SessionImpl
checkOpen();
pulseTransactionCoordinator();
final EvictEvent event = new EvictEvent( object, this );
fastSessionServices.eventListenerGroup_EVICT.fireEventOnEachListener( event, EvictEventListener::onEvict );
fastSessionServices.eventListenerGroup_EVICT
.fireEventOnEachListener( event, EvictEventListener::onEvict );
delayedAfterCompletion();
}
@ -1353,7 +1377,8 @@ public class SessionImpl
return false;
}
AutoFlushEvent event = new AutoFlushEvent( querySpaces, this );
fastSessionServices.eventListenerGroup_AUTO_FLUSH.fireEventOnEachListener( event, AutoFlushEventListener::onAutoFlush );
fastSessionServices.eventListenerGroup_AUTO_FLUSH
.fireEventOnEachListener( event, AutoFlushEventListener::onAutoFlush );
return event.isFlushRequired();
}
@ -1367,7 +1392,8 @@ public class SessionImpl
return true;
}
DirtyCheckEvent event = new DirtyCheckEvent( this );
fastSessionServices.eventListenerGroup_DIRTY_CHECK.fireEventOnEachListener( event, DirtyCheckEventListener::onDirtyCheck );
fastSessionServices.eventListenerGroup_DIRTY_CHECK
.fireEventOnEachListener( event, DirtyCheckEventListener::onDirtyCheck );
delayedAfterCompletion();
return event.isDirty();
}
@ -1388,7 +1414,8 @@ public class SessionImpl
}
FlushEvent event = new FlushEvent( this );
fastSessionServices.eventListenerGroup_FLUSH.fireEventOnEachListener( event, FlushEventListener::onFlush );
fastSessionServices.eventListenerGroup_FLUSH
.fireEventOnEachListener( event, FlushEventListener::onFlush );
delayedAfterCompletion();
}
catch ( RuntimeException e ) {
@ -1676,7 +1703,8 @@ public class SessionImpl
checkOpenOrWaitingForAutoClose();
pulseTransactionCoordinator();
InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this );
fastSessionServices.eventListenerGroup_INIT_COLLECTION.fireEventOnEachListener( event, InitializeCollectionEventListener::onInitializeCollection );
fastSessionServices.eventListenerGroup_INIT_COLLECTION
.fireEventOnEachListener( event, InitializeCollectionEventListener::onInitializeCollection );
delayedAfterCompletion();
}
@ -2576,7 +2604,8 @@ public class SessionImpl
private Map<String, Object> computeCurrentSessionProperties() {
final HashMap<String, Object> map = new HashMap<>( fastSessionServices.defaultSessionProperties );
//The FLUSH_MODE is always set at Session creation time, so it needs special treatment to not eagerly initialize this Map:
//The FLUSH_MODE is always set at Session creation time,
//so it needs special treatment to not eagerly initialize this Map:
map.put( AvailableSettings.FLUSH_MODE, getHibernateFlushMode().name() );
return map;
}

View File

@ -125,7 +125,7 @@ public interface ClassMetadata {
*/
@Deprecated(since = "5.3")
@SuppressWarnings({"UnusedDeclaration"})
default Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session)
default Object[] getPropertyValuesToInsert(Object entity, Map<Object,Object> mergeMap, SessionImplementor session)
throws HibernateException {
return getPropertyValuesToInsert( entity, mergeMap, (SharedSessionContractImplementor) session );
}
@ -134,7 +134,8 @@ public interface ClassMetadata {
* Return the values of the mapped properties of the object
*/
@SuppressWarnings( {"UnusedDeclaration"})
Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SharedSessionContractImplementor session) throws HibernateException;
Object[] getPropertyValuesToInsert(Object entity, Map<Object,Object> mergeMap, SharedSessionContractImplementor session)
throws HibernateException;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -144,7 +145,7 @@ public interface ClassMetadata {
/**
* The persistent class, or null
*/
Class getMappedClass();
Class<?> getMappedClass();
/**
* Create a class instance initialized with the given identifier

View File

@ -5162,7 +5162,10 @@ public abstract class AbstractEntityPersister
}
@Override
public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SharedSessionContractImplementor session)
public Object[] getPropertyValuesToInsert(
Object entity,
Map<Object,Object> mergeMap,
SharedSessionContractImplementor session)
throws HibernateException {
if ( shouldGetAllProperties( entity ) && accessOptimizer != null ) {
return accessOptimizer.getPropertyValues( entity );

View File

@ -760,7 +760,7 @@ public interface EntityPersister
/**
* Return the values of the insertable properties of the object (including backrefs)
*/
Object[] getPropertyValuesToInsert(Object object, Map mergeMap, SharedSessionContractImplementor session);
Object[] getPropertyValuesToInsert(Object object, Map<Object,Object> mergeMap, SharedSessionContractImplementor session);
/**
* Perform a select to retrieve the values of any generated properties

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.orm.test.events;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
@ -16,6 +14,7 @@ import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.EventType;
@ -135,7 +134,7 @@ public class CallbackTest extends BaseCoreFunctionalTestCase {
public void onDelete(DeleteEvent event) throws HibernateException {
}
public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {
public void onDelete(DeleteEvent event, DeleteContext transientEntities) throws HibernateException {
}
}
}

View File

@ -7,7 +7,6 @@
package org.hibernate.orm.test.jpa.model;
import java.sql.Connection;
import java.util.IdentityHashMap;
import org.hibernate.Session;
import org.hibernate.boot.Metadata;
@ -27,6 +26,7 @@ import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.FlushEntityEventListener;
import org.hibernate.event.spi.FlushEventListener;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.PersistEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.proxy.EntityNotFoundDelegate;
@ -132,7 +132,7 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
public static class JPAPersistOnFlushEventListener extends JPAPersistEventListener {
@Override
protected CascadingAction getCascadeAction() {
protected CascadingAction<PersistContext> getCascadeAction() {
return CascadingActions.PERSIST_ON_FLUSH;
}
}
@ -142,13 +142,13 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener();
@Override
protected CascadingAction getCascadingAction() {
protected CascadingAction<PersistContext> getCascadingAction() {
return CascadingActions.PERSIST_ON_FLUSH;
}
@Override
protected Object getAnything() {
return new IdentityHashMap( 10 );
protected PersistContext getContext() {
return PersistContext.create();
}
}
@ -157,13 +157,13 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
public static final FlushEventListener INSTANCE = new JPAFlushEventListener();
@Override
protected CascadingAction getCascadingAction() {
protected CascadingAction<PersistContext> getCascadingAction() {
return CascadingActions.PERSIST_ON_FLUSH;
}
@Override
protected Object getAnything() {
return new IdentityHashMap( 10 );
protected PersistContext getContext() {
return PersistContext.create();
}
}