HHH-18169 big cleanup of lock/refresh in SessionImpl and collaborators

this was a big mess with no consistency between different overloads of
the same-named method of Session, not to mention different methods

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-09-01 12:52:26 +02:00
parent f45e3db4b0
commit 83cdeb81b6
6 changed files with 270 additions and 331 deletions

View File

@ -232,8 +232,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
} }
private static boolean isTransactionCoordinatorShared(SessionCreationOptions options) { private static boolean isTransactionCoordinatorShared(SessionCreationOptions options) {
return options instanceof SharedSessionCreationOptions return options instanceof SharedSessionCreationOptions sharedSessionCreationOptions
&& ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared(); && sharedSessionCreationOptions.isTransactionCoordinatorShared();
} }
protected final void setUpMultitenancy(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) { protected final void setUpMultitenancy(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) {

View File

@ -68,7 +68,6 @@ import org.hibernate.jpa.LegacySpecHints;
import org.hibernate.jpa.SpecHints; import org.hibernate.jpa.SpecHints;
import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.LockOptionsHelper;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy; import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
@ -88,6 +87,7 @@ import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.internal.LockOptionsHelper.applyPropertiesToLockOptions;
/** /**
* Internal component. * Internal component.
@ -282,9 +282,9 @@ public final class FastSessionServices {
} }
private static LockOptions initializeDefaultLockOptions(final Map<String, Object> defaultSessionProperties) { private static LockOptions initializeDefaultLockOptions(final Map<String, Object> defaultSessionProperties) {
LockOptions def = new LockOptions(); final LockOptions lockOptions = new LockOptions();
LockOptionsHelper.applyPropertiesToLockOptions( defaultSessionProperties, () -> def ); applyPropertiesToLockOptions( defaultSessionProperties, () -> lockOptions );
return def; return lockOptions;
} }
private static <T> EventListenerGroup<T> listeners(EventListenerRegistry elr, EventType<T> type) { private static <T> EventListenerGroup<T> listeners(EventListenerRegistry elr, EventType<T> type) {

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * 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>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.jpa.internal.util; package org.hibernate.internal;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -13,12 +13,13 @@ import jakarta.persistence.PessimisticLockScope;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import static jakarta.persistence.PessimisticLockScope.EXTENDED;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
public final class LockOptionsHelper { final class LockOptionsHelper {
private LockOptionsHelper() { private LockOptionsHelper() {
//utility class, not to be constructed //utility class, not to be constructed
@ -30,60 +31,50 @@ public final class LockOptionsHelper {
* nothing to set. * nothing to set.
* *
* @param props The configuration properties * @param props The configuration properties
* @param lockOptionsSupplier The reference to the lock to modify * @param lockOptions The reference to the lock to modify
*/ */
public static void applyPropertiesToLockOptions(final Map<String, Object> props, final Supplier<LockOptions> lockOptionsSupplier) { public static void applyPropertiesToLockOptions(Map<String, Object> props, Supplier<LockOptions> lockOptions) {
applyScope( props, lockOptions );
applyTimeout( props, lockOptions );
}
private static void applyScope(Map<String, Object> props, Supplier<LockOptions> lockOptions) {
String lockScopeHint = JPA_LOCK_SCOPE; String lockScopeHint = JPA_LOCK_SCOPE;
Object lockScope = props.get( lockScopeHint ); Object lockScope = props.get( lockScopeHint );
if ( lockScope == null ) { if ( lockScope == null ) {
lockScopeHint = JAKARTA_LOCK_SCOPE; lockScopeHint = JAKARTA_LOCK_SCOPE;
lockScope = props.get( lockScopeHint ); lockScope = props.get( lockScopeHint );
} }
if ( lockScope instanceof String && PessimisticLockScope.valueOf( (String) lockScope ) == PessimisticLockScope.EXTENDED ) {
lockOptionsSupplier.get().setScope( true ); if ( lockScope instanceof String string ) {
lockOptions.get().setScope( EXTENDED.name().equalsIgnoreCase( string ) );
} }
else if ( lockScope instanceof PessimisticLockScope ) { else if ( lockScope instanceof PessimisticLockScope ) {
boolean extended = PessimisticLockScope.EXTENDED.equals( lockScope ); lockOptions.get().setScope( EXTENDED == lockScope );
lockOptionsSupplier.get().setScope( extended );
} }
else if ( lockScope != null ) { else if ( lockScope != null ) {
throw new PersistenceException( "Unable to parse " + lockScopeHint + ": " + lockScope ); throw new PersistenceException( "Unable to parse " + lockScopeHint + ": " + lockScope );
} }
}
private static void applyTimeout(Map<String, Object> props, Supplier<LockOptions> lockOptions) {
String timeoutHint = JPA_LOCK_TIMEOUT; String timeoutHint = JPA_LOCK_TIMEOUT;
Object lockTimeout = props.get( timeoutHint ); Object lockTimeout = props.get( timeoutHint );
if (lockTimeout == null) { if (lockTimeout == null) {
timeoutHint = JAKARTA_LOCK_TIMEOUT; timeoutHint = JAKARTA_LOCK_TIMEOUT;
lockTimeout = props.get( timeoutHint ); lockTimeout = props.get( timeoutHint );
} }
int timeout = 0;
boolean timeoutSet = false; if ( lockTimeout instanceof String string ) {
if ( lockTimeout instanceof String ) { lockOptions.get().setTimeOut( Integer.parseInt( string ) );
timeout = Integer.parseInt( (String) lockTimeout );
timeoutSet = true;
} }
else if ( lockTimeout instanceof Number ) { else if ( lockTimeout instanceof Number number ) {
timeout = ( (Number) lockTimeout ).intValue(); int timeout = number.intValue();
timeoutSet = true; lockOptions.get().setTimeOut( timeout );
} }
else if ( lockTimeout != null ) { else if ( lockTimeout != null ) {
throw new PersistenceException( "Unable to parse " + timeoutHint + ": " + lockTimeout ); throw new PersistenceException( "Unable to parse " + timeoutHint + ": " + lockTimeout );
} }
if ( timeoutSet ) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
lockOptionsSupplier.get().setTimeOut( LockOptions.SKIP_LOCKED );
}
else if ( timeout < 0 ) {
lockOptionsSupplier.get().setTimeOut( LockOptions.WAIT_FOREVER );
}
else if ( timeout == 0 ) {
lockOptionsSupplier.get().setTimeOut( LockOptions.NO_WAIT );
}
else {
lockOptionsSupplier.get().setTimeOut( timeout );
}
}
} }
} }

View File

@ -50,7 +50,6 @@ import org.hibernate.SessionEventListener;
import org.hibernate.SessionException; import org.hibernate.SessionException;
import org.hibernate.SharedSessionBuilder; import org.hibernate.SharedSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess; import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.TransientObjectException;
import org.hibernate.TypeMismatchException; import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException; import org.hibernate.UnknownProfileException;
import org.hibernate.UnresolvableObjectException; import org.hibernate.UnresolvableObjectException;
@ -61,6 +60,7 @@ import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.NonContextualLobCreator; import org.hibernate.engine.jdbc.NonContextualLobCreator;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.spi.ActionQueue; import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.ActionQueue.TransactionCompletionProcesses;
import org.hibernate.engine.spi.EffectiveEntityGraph; import org.hibernate.engine.spi.EffectiveEntityGraph;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
@ -121,7 +121,6 @@ import org.hibernate.loader.internal.LoadAccessContext;
import org.hibernate.loader.internal.NaturalIdLoadAccessImpl; import org.hibernate.loader.internal.NaturalIdLoadAccessImpl;
import org.hibernate.loader.internal.SimpleNaturalIdLoadAccessImpl; import org.hibernate.loader.internal.SimpleNaturalIdLoadAccessImpl;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall; import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
@ -161,6 +160,7 @@ import jakarta.persistence.criteria.CriteriaSelect;
import jakarta.persistence.metamodel.Metamodel; import jakarta.persistence.metamodel.Metamodel;
import static java.lang.Boolean.parseBoolean; import static java.lang.Boolean.parseBoolean;
import static java.lang.Integer.parseInt;
import static java.lang.System.currentTimeMillis; import static java.lang.System.currentTimeMillis;
import static java.util.Collections.unmodifiableMap; import static java.util.Collections.unmodifiableMap;
import static org.hibernate.CacheMode.fromJpaModes; import static org.hibernate.CacheMode.fromJpaModes;
@ -193,7 +193,8 @@ import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT; import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_QUERY_TIMEOUT; import static org.hibernate.jpa.SpecHints.HINT_SPEC_QUERY_TIMEOUT;
import static org.hibernate.jpa.internal.util.CacheModeHelper.interpretCacheMode; import static org.hibernate.jpa.internal.util.CacheModeHelper.interpretCacheMode;
import static org.hibernate.jpa.internal.util.LockOptionsHelper.applyPropertiesToLockOptions; import static org.hibernate.internal.LockOptionsHelper.applyPropertiesToLockOptions;
import static org.hibernate.pretty.MessageHelper.infoString;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/** /**
@ -237,60 +238,60 @@ public class SessionImpl
private transient TransactionObserver transactionObserver; private transient TransactionObserver transactionObserver;
// TODO: this is unused and can be removed
private transient boolean isEnforcingFetchGraph;
public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
super( factory, options ); super( factory, options );
final HibernateMonitoringEvent sessionOpenEvent = getEventManager().beginSessionOpenEvent(); final HibernateMonitoringEvent sessionOpenEvent = getEventManager().beginSessionOpenEvent();
try {
persistenceContext = createPersistenceContext(); persistenceContext = createPersistenceContext();
actionQueue = createActionQueue(); actionQueue = createActionQueue();
autoClear = options.shouldAutoClear(); autoClear = options.shouldAutoClear();
autoClose = options.shouldAutoClose(); autoClose = options.shouldAutoClose();
if ( options instanceof SharedSessionCreationOptions ) { setUpTransactionCompletionProcesses( options );
final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options;
final ActionQueue.TransactionCompletionProcesses transactionCompletionProcesses loadQueryInfluencers = new LoadQueryInfluencers( factory, options );
= sharedOptions.getTransactionCompletionProcesses();
if ( sharedOptions.isTransactionCoordinatorShared() && transactionCompletionProcesses != null ) { if ( properties != null ) {
actionQueue.setTransactionCompletionProcesses( //There might be custom properties for this session that affect the LockOptions state
transactionCompletionProcesses, applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite );
true }
); setCacheMode( fastSessionServices.initialSessionCacheMode );
// NOTE : pulse() already handles auto-join-ability correctly
getTransactionCoordinator().pulse();
// do not override explicitly set flush mode ( SessionBuilder#flushMode() )
if ( getHibernateFlushMode() == null ) {
setHibernateFlushMode( getInitialFlushMode() );
}
setUpMultitenancy( factory, loadQueryInfluencers );
final StatisticsImplementor statistics = factory.getStatistics();
if ( statistics.isStatisticsEnabled() ) {
statistics.openSession();
}
if ( log.isTraceEnabled() ) {
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() );
} }
} }
finally {
loadQueryInfluencers = new LoadQueryInfluencers( factory, options ); getEventManager().completeSessionOpenEvent( sessionOpenEvent, this );
final StatisticsImplementor statistics = factory.getStatistics();
if ( statistics.isStatisticsEnabled() ) {
statistics.openSession();
} }
}
if ( properties != null ) { private void setUpTransactionCompletionProcesses(SessionCreationOptions options) {
//There might be custom properties for this session that affect the LockOptions state if ( options instanceof SharedSessionCreationOptions sharedOptions
applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); && sharedOptions.isTransactionCoordinatorShared() ) {
final TransactionCompletionProcesses processes = sharedOptions.getTransactionCompletionProcesses();
if ( processes != null ) {
actionQueue.setTransactionCompletionProcesses( processes, true );
}
} }
setCacheMode( fastSessionServices.initialSessionCacheMode );
// NOTE : pulse() already handles auto-join-ability correctly
getTransactionCoordinator().pulse();
// do not override explicitly set flush mode ( SessionBuilder#flushMode() )
if ( getHibernateFlushMode() == null ) {
setHibernateFlushMode( getInitialFlushMode() );
}
setUpMultitenancy( factory, loadQueryInfluencers );
if ( log.isTraceEnabled() ) {
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() );
}
getEventManager().completeSessionOpenEvent( sessionOpenEvent, this );
} }
private FlushMode getInitialFlushMode() { private FlushMode getInitialFlushMode() {
@ -346,7 +347,7 @@ public class SessionImpl
HINT_JAVAEE_LOCK_TIMEOUT, HINT_JAVAEE_LOCK_TIMEOUT,
this::getSessionProperty, this::getSessionProperty,
// treat WAIT_FOREVER the same as null // treat WAIT_FOREVER the same as null
(value) -> !Integer.valueOf( LockOptions.WAIT_FOREVER ).equals( value ) value -> !Integer.valueOf( LockOptions.WAIT_FOREVER ).equals( value )
); );
if ( specLockTimeout != null ) { if ( specLockTimeout != null ) {
query.setHint( HINT_SPEC_LOCK_TIMEOUT, specLockTimeout ); query.setHint( HINT_SPEC_LOCK_TIMEOUT, specLockTimeout );
@ -354,12 +355,9 @@ public class SessionImpl
} }
private Object getSessionProperty(final String name) { private Object getSessionProperty(final String name) {
if ( properties == null ) { return properties == null
return fastSessionServices.defaultSessionProperties.get( name ); ? fastSessionServices.defaultSessionProperties.get( name )
} : properties.get( name );
else {
return properties.get( name );
}
} }
@Override @Override
@ -401,12 +399,11 @@ public class SessionImpl
if ( getFactory().getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) { if ( getFactory().getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) {
throw new IllegalStateException( "Illegal call to #close() on already closed Session/EntityManager" ); throw new IllegalStateException( "Illegal call to #close() on already closed Session/EntityManager" );
} }
log.trace( "Already closed" ); log.trace( "Already closed" );
return;
} }
else {
closeWithoutOpenChecks(); closeWithoutOpenChecks();
}
} }
public void closeWithoutOpenChecks() throws HibernateException { public void closeWithoutOpenChecks() throws HibernateException {
@ -416,15 +413,13 @@ public class SessionImpl
final EventManager eventManager = getEventManager(); final EventManager eventManager = getEventManager();
final HibernateMonitoringEvent sessionClosedEvent = eventManager.beginSessionClosedEvent(); final HibernateMonitoringEvent sessionClosedEvent = eventManager.beginSessionClosedEvent();
// todo : we want this check if usage is JPA, but not native Hibernate usage
final SessionFactoryImplementor sessionFactory = getSessionFactory();
try { try {
if ( sessionFactory.getSessionFactoryOptions().isJpaBootstrap() ) { if ( isJpaBootstrap() ) {
// Original hibernate-entitymanager EM#close behavior // Original HEM close behavior
checkSessionFactoryOpen(); checkSessionFactoryOpen();
checkOpenOrWaitingForAutoClose(); checkOpenOrWaitingForAutoClose();
if ( fastSessionServices.discardOnClose || !isTransactionInProgressAndNotMarkedForRollback() ) { if ( fastSessionServices.discardOnClose
|| !isTransactionInProgressAndNotMarkedForRollback() ) {
super.close(); super.close();
} }
else { else {
@ -433,19 +428,23 @@ public class SessionImpl
} }
} }
else { else {
// Regular Hibernate behavior
super.close(); super.close();
} }
} }
finally { finally {
final StatisticsImplementor statistics = sessionFactory.getStatistics(); final StatisticsImplementor statistics = getSessionFactory().getStatistics();
if ( statistics.isStatisticsEnabled() ) { if ( statistics.isStatisticsEnabled() ) {
statistics.closeSession(); statistics.closeSession();
} }
eventManager.completeSessionClosedEvent( sessionClosedEvent, this ); eventManager.completeSessionClosedEvent( sessionClosedEvent, this );
} }
} }
private boolean isJpaBootstrap() {
return getSessionFactory().getSessionFactoryOptions().isJpaBootstrap();
}
private boolean isTransactionInProgressAndNotMarkedForRollback() { private boolean isTransactionInProgressAndNotMarkedForRollback() {
if ( waitingForAutoClose ) { if ( waitingForAutoClose ) {
return getSessionFactory().isOpen() return getSessionFactory().isOpen()
@ -619,10 +618,8 @@ public class SessionImpl
@Override @Override
public void delayedAfterCompletion() { public void delayedAfterCompletion() {
TransactionCoordinator coordinator = getTransactionCoordinator(); if ( getTransactionCoordinator() instanceof JtaTransactionCoordinatorImpl impl ) {
if ( coordinator instanceof JtaTransactionCoordinatorImpl ) { impl.getSynchronizationCallbackCoordinator().processAnyDelayedAfterCompletion();
( (JtaTransactionCoordinatorImpl) coordinator).getSynchronizationCallbackCoordinator()
.processAnyDelayedAfterCompletion();
} }
} }
@ -653,17 +650,36 @@ public class SessionImpl
fireLock( new LockEvent( object, lockMode, this ) ); fireLock( new LockEvent( object, lockMode, this ) );
} }
private void fireLock(Object object, LockOptions options) {
fireLock( new LockEvent( object, options, this ) );
}
private void fireLock(LockEvent event) { private void fireLock(LockEvent event) {
checkOpen(); checkOpen();
checkEntityManaged( event.getEntityName(), event.getObject() ); checkEntityManaged( event.getEntityName(), event.getObject() );
pulseTransactionCoordinator(); try {
fastSessionServices.eventListenerGroup_LOCK pulseTransactionCoordinator();
.fireEventOnEachListener( event, LockEventListener::onLock ); checkTransactionNeededForLock( event.getLockMode() );
delayedAfterCompletion(); fastSessionServices.eventListenerGroup_LOCK
.fireEventOnEachListener( event, LockEventListener::onLock );
}
catch ( RuntimeException e ) {
convertIfJpaBootstrap( e, event.getLockOptions() );
}
finally {
delayedAfterCompletion();
}
}
private void convertIfJpaBootstrap(RuntimeException exception, LockOptions lockOptions) {
if ( !isJpaBootstrap() && exception instanceof HibernateException ) {
throw exception;
}
else if ( exception instanceof MappingException ) {
// I believe this is now obsolete everywhere we do it,
// but we do it everywhere else, so let's do it here
throw getExceptionConverter()
.convert( new IllegalArgumentException( exception.getMessage(), exception ) );
}
else {
throw getExceptionConverter().convert( exception, lockOptions );
}
} }
// persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -730,9 +746,8 @@ public class SessionImpl
} }
private void firePersist(final PersistContext copiedAlready, final PersistEvent event) { private void firePersist(final PersistContext copiedAlready, final PersistEvent event) {
pulseTransactionCoordinator();
try { try {
pulseTransactionCoordinator();
//Uses a capturing lambda in this case as we need to carry the additional Map parameter: //Uses a capturing lambda in this case as we need to carry the additional Map parameter:
fastSessionServices.eventListenerGroup_PERSIST fastSessionServices.eventListenerGroup_PERSIST
.fireEventOnEachListener( event, copiedAlready, PersistEventListener::onPersist ); .fireEventOnEachListener( event, copiedAlready, PersistEventListener::onPersist );
@ -878,13 +893,13 @@ public class SessionImpl
log.tracef( log.tracef(
"%s remove orphan before updates: [%s]", "%s remove orphan before updates: [%s]",
timing, timing,
entityEntry == null ? entityName : MessageHelper.infoString( entityName, entityEntry.getId() ) entityEntry == null ? entityName : infoString( entityName, entityEntry.getId() )
); );
} }
} }
private void fireDelete(final DeleteEvent event) { private void fireDelete(final DeleteEvent event) {
try{ try {
pulseTransactionCoordinator(); pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_DELETE fastSessionServices.eventListenerGroup_DELETE
.fireEventOnEachListener( event, DeleteEventListener::onDelete ); .fireEventOnEachListener( event, DeleteEventListener::onDelete );
@ -905,7 +920,7 @@ public class SessionImpl
} }
private void fireDelete(final DeleteEvent event, final DeleteContext transientEntities) { private void fireDelete(final DeleteEvent event, final DeleteContext transientEntities) {
try{ try {
pulseTransactionCoordinator(); pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_DELETE fastSessionServices.eventListenerGroup_DELETE
.fireEventOnEachListener( event, transientEntities, DeleteEventListener::onDelete ); .fireEventOnEachListener( event, transientEntities, DeleteEventListener::onDelete );
@ -956,9 +971,8 @@ public class SessionImpl
@Override @Override
public Object immediateLoad(String entityName, Object id) throws HibernateException { public Object immediateLoad(String entityName, Object id) throws HibernateException {
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
final EntityPersister persister = getFactory().getMappingMetamodel() final EntityPersister persister = requireEntityPersister( entityName );
.getEntityDescriptor( entityName ); log.debugf( "Initializing proxy: %s", infoString( persister, id, getFactory() ) );
log.debugf( "Initializing proxy: %s", MessageHelper.infoString( persister, id, getFactory() ) );
} }
LoadEvent event = loadEvent; LoadEvent event = loadEvent;
loadEvent = null; loadEvent = null;
@ -1140,43 +1154,35 @@ public class SessionImpl
@Override @Override
public void refresh(Object object) throws HibernateException { public void refresh(Object object) throws HibernateException {
checkOpen();
fireRefresh( new RefreshEvent( object, this ) ); fireRefresh( new RefreshEvent( object, this ) );
} }
@Override @Override
public void refresh(Object object, LockMode lockMode) throws HibernateException { public void refresh(Object object, LockMode lockMode) throws HibernateException {
checkOpen();
fireRefresh( new RefreshEvent( object, lockMode, this ) ); fireRefresh( new RefreshEvent( object, lockMode, this ) );
} }
@Override @Override
public void refresh(Object object, LockOptions lockOptions) throws HibernateException { public void refresh(Object object, LockOptions lockOptions) throws HibernateException {
checkOpen();
fireRefresh( new RefreshEvent( object, lockOptions, this ) ); fireRefresh( new RefreshEvent( object, lockOptions, this ) );
} }
@Override @Override
public void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException { public void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException {
checkOpenOrWaitingForAutoClose();
fireRefresh( refreshedAlready, new RefreshEvent( entityName, object, this ) ); fireRefresh( refreshedAlready, new RefreshEvent( entityName, object, this ) );
} }
private void fireRefresh(final RefreshEvent event) { private void fireRefresh(final RefreshEvent event) {
checkOpen();
checkEntityManaged( event.getEntityName(), event.getObject() );
try { try {
checkEntityManaged( event.getEntityName(), event.getObject() );
pulseTransactionCoordinator(); pulseTransactionCoordinator();
checkTransactionNeededForLock( event.getLockMode() );
fastSessionServices.eventListenerGroup_REFRESH fastSessionServices.eventListenerGroup_REFRESH
.fireEventOnEachListener( event, RefreshEventListener::onRefresh ); .fireEventOnEachListener( event, RefreshEventListener::onRefresh );
} }
catch (RuntimeException e) { catch ( RuntimeException e ) {
if ( !getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) { convertIfJpaBootstrap( e, event.getLockOptions() );
if ( e instanceof HibernateException ) {
throw e;
}
}
//including HibernateException
throw getExceptionConverter().convert( e );
} }
finally { finally {
delayedAfterCompletion(); delayedAfterCompletion();
@ -1184,15 +1190,14 @@ public class SessionImpl
} }
private void fireRefresh(final RefreshContext refreshedAlready, final RefreshEvent event) { private void fireRefresh(final RefreshContext refreshedAlready, final RefreshEvent event) {
// called from cascades
checkOpenOrWaitingForAutoClose();
checkEntityManaged( event.getEntityName(), event.getObject() );
try { try {
checkEntityManaged( event.getEntityName(), event.getObject() );
pulseTransactionCoordinator(); pulseTransactionCoordinator();
fastSessionServices.eventListenerGroup_REFRESH fastSessionServices.eventListenerGroup_REFRESH
.fireEventOnEachListener( event, refreshedAlready, RefreshEventListener::onRefresh ); .fireEventOnEachListener( event, refreshedAlready, RefreshEventListener::onRefresh );
} }
catch (RuntimeException e) {
throw getExceptionConverter().convert( e );
}
finally { finally {
delayedAfterCompletion(); delayedAfterCompletion();
} }
@ -1304,17 +1309,14 @@ public class SessionImpl
} }
private void doFlush() { private void doFlush() {
pulseTransactionCoordinator();
checkTransactionNeededForUpdateOperation();
try { try {
pulseTransactionCoordinator();
checkTransactionNeededForUpdateOperation();
if ( persistenceContext.getCascadeLevel() > 0 ) { if ( persistenceContext.getCascadeLevel() > 0 ) {
throw new HibernateException( "Flush during cascade is dangerous" ); throw new HibernateException( "Flush during cascade is dangerous" );
} }
FlushEvent event = new FlushEvent( this );
fastSessionServices.eventListenerGroup_FLUSH fastSessionServices.eventListenerGroup_FLUSH
.fireEventOnEachListener( event, FlushEventListener::onFlush ); .fireEventOnEachListener( new FlushEvent( this ), FlushEventListener::onFlush );
delayedAfterCompletion(); delayedAfterCompletion();
} }
catch ( RuntimeException e ) { catch ( RuntimeException e ) {
@ -1338,7 +1340,7 @@ public class SessionImpl
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
log.debugf( log.debugf(
"Flushing to force deletion of re-saved object: %s", "Flushing to force deletion of re-saved object: %s",
MessageHelper.infoString( key.getPersister(), key.getIdentifier(), getFactory() ) infoString( key.getPersister(), key.getIdentifier(), getFactory() )
); );
} }
@ -1355,10 +1357,7 @@ public class SessionImpl
@Override @Override
public Object instantiate(String entityName, Object id) throws HibernateException { public Object instantiate(String entityName, Object id) throws HibernateException {
final EntityPersister persister = getFactory().getRuntimeMetamodels() return instantiate( requireEntityPersister( entityName ), id );
.getMappingMetamodel()
.getEntityDescriptor( entityName );
return instantiate( persister, id );
} }
/** /**
@ -1368,11 +1367,8 @@ public class SessionImpl
public Object instantiate(EntityPersister persister, Object id) throws HibernateException { public Object instantiate(EntityPersister persister, Object id) throws HibernateException {
checkOpenOrWaitingForAutoClose(); checkOpenOrWaitingForAutoClose();
pulseTransactionCoordinator(); pulseTransactionCoordinator();
Object result = getInterceptor().instantiate( Object result = getInterceptor()
persister.getEntityName(), .instantiate( persister.getEntityName(), persister.getRepresentationStrategy(), id );
persister.getRepresentationStrategy(),
id
);
if ( result == null ) { if ( result == null ) {
result = persister.instantiate( id, this ); result = persister.instantiate( id, this );
} }
@ -1384,9 +1380,7 @@ public class SessionImpl
public EntityPersister getEntityPersister(final String entityName, final Object object) { public EntityPersister getEntityPersister(final String entityName, final Object object) {
checkOpenOrWaitingForAutoClose(); checkOpenOrWaitingForAutoClose();
if ( entityName == null ) { if ( entityName == null ) {
return getFactory().getRuntimeMetamodels() return requireEntityPersister( guessEntityName( object ) );
.getMappingMetamodel()
.getEntityDescriptor( guessEntityName( object ) );
} }
else { else {
// try block is a hack around fact that currently tuplizers are not // try block is a hack around fact that currently tuplizers are not
@ -1395,9 +1389,7 @@ public class SessionImpl
// influence this decision if we were not able to based on the // influence this decision if we were not able to based on the
// given entityName // given entityName
try { try {
return getFactory().getRuntimeMetamodels() return requireEntityPersister( entityName )
.getMappingMetamodel()
.getEntityDescriptor( entityName )
.getSubclassEntityPersister( object, getFactory() ); .getSubclassEntityPersister( object, getFactory() );
} }
catch ( HibernateException e ) { catch ( HibernateException e ) {
@ -1488,7 +1480,7 @@ public class SessionImpl
// A session is considered to contain an entity only if the entity has // A session is considered to contain an entity only if the entity has
// an entry in the session's persistence context and the entry reports // an entry in the session's persistence context and the entry reports
// that the entity has not been removed // that the entity has not been removed
EntityEntry entry = persistenceContext.getEntry( object ); final EntityEntry entry = persistenceContext.getEntry( object );
delayedAfterCompletion(); delayedAfterCompletion();
if ( entry == null ) { if ( entry == null ) {
@ -1497,14 +1489,16 @@ public class SessionImpl
try { try {
final String entityName = getEntityNameResolver().resolveEntityName( object ); final String entityName = getEntityNameResolver().resolveEntityName( object );
if ( entityName == null ) { if ( entityName == null ) {
throw new IllegalArgumentException( "Could not resolve entity name for class '" + object.getClass() + "'" ); throw new IllegalArgumentException( "Could not resolve entity name for class '"
+ object.getClass() + "'" );
}
else {
requireEntityPersister( entityName );
} }
getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
} }
catch ( HibernateException e ) { catch ( HibernateException e ) {
throw new IllegalArgumentException( "Class '" + object.getClass() + "' is not an entity class", e ); throw new IllegalArgumentException( "Class '" + object.getClass()
+ "' is not an entity class", e );
} }
} }
return false; return false;
@ -1535,8 +1529,7 @@ public class SessionImpl
if ( lazyInitializer == null && persistenceContext.getEntry( object ) == null ) { if ( lazyInitializer == null && persistenceContext.getEntry( object ) == null ) {
// check if it is an entity -> if not throw an exception (per JPA) // check if it is an entity -> if not throw an exception (per JPA)
try { try {
getFactory().getMappingMetamodel() requireEntityPersister( entityName );
.getEntityDescriptor( entityName );
} }
catch (HibernateException e) { catch (HibernateException e) {
throw new IllegalArgumentException( "Not an entity [" + entityName + "] : " + object ); throw new IllegalArgumentException( "Not an entity [" + entityName + "] : " + object );
@ -1636,9 +1629,9 @@ public class SessionImpl
public void initializeCollection(PersistentCollection<?> collection, boolean writing) { public void initializeCollection(PersistentCollection<?> collection, boolean writing) {
checkOpenOrWaitingForAutoClose(); checkOpenOrWaitingForAutoClose();
pulseTransactionCoordinator(); pulseTransactionCoordinator();
InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this );
fastSessionServices.eventListenerGroup_INIT_COLLECTION fastSessionServices.eventListenerGroup_INIT_COLLECTION
.fireEventOnEachListener( event, InitializeCollectionEventListener::onInitializeCollection ); .fireEventOnEachListener( new InitializeCollectionEvent( collection, this ),
InitializeCollectionEventListener::onInitializeCollection );
delayedAfterCompletion(); delayedAfterCompletion();
} }
@ -1721,8 +1714,10 @@ public class SessionImpl
@Override @Override
public String toString() { public String toString() {
final StringBuilder string = new StringBuilder( 500 ) final StringBuilder string =
.append( "SessionImpl(" ).append( System.identityHashCode( this ) ); new StringBuilder( 500 )
.append( "SessionImpl(" )
.append( System.identityHashCode( this ) );
if ( !isClosed() ) { if ( !isClosed() ) {
if ( log.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
string.append( persistenceContext ) string.append( persistenceContext )
@ -2134,7 +2129,7 @@ public class SessionImpl
} }
@Override @Override
public ActionQueue.TransactionCompletionProcesses getTransactionCompletionProcesses() { public TransactionCompletionProcesses getTransactionCompletionProcesses() {
return shareTransactionContext ? return shareTransactionContext ?
session.getActionQueue().getTransactionCompletionProcesses() : session.getActionQueue().getTransactionCompletionProcesses() :
null; null;
@ -2175,15 +2170,11 @@ public class SessionImpl
} }
private EntityPersister requireEntityPersister(Class<?> entityClass) { private EntityPersister requireEntityPersister(Class<?> entityClass) {
return getFactory().getRuntimeMetamodels() return getFactory().getMappingMetamodel().getEntityDescriptor( entityClass );
.getMappingMetamodel()
.getEntityDescriptor( entityClass );
} }
private EntityPersister requireEntityPersister(String entityName) { private EntityPersister requireEntityPersister(String entityName) {
return getFactory().getRuntimeMetamodels() return getFactory().getMappingMetamodel().getEntityDescriptor( entityName );
.getMappingMetamodel()
.getEntityDescriptor( entityName );
} }
@Override @Override
@ -2232,26 +2223,6 @@ public class SessionImpl
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HibernateEntityManagerImplementor impl
// @Override
// public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties) {
// LockOptions lockOptions = new LockOptions();
// if ( this.lockOptions != null ) { //otherwise the default LockOptions constructor is the same as DEFAULT_LOCK_OPTIONS
// LockOptions.copy( this.lockOptions, lockOptions );
// }
// lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
// if ( properties != null ) {
// LockOptionsHelper.applyPropertiesToLockOptions( properties, () -> lockOptions );
// }
// return lockOptions;
// }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EntityManager impl // EntityManager impl
@ -2292,13 +2263,13 @@ public class SessionImpl
LockOptions lockOptions = null; LockOptions lockOptions = null;
try { try {
if ( lockModeType != null ) { if ( lockModeType != null ) {
checkTransactionNeededForLock( lockModeType ); checkTransactionNeededForLock( LockModeTypeHelper.getLockMode( lockModeType ) );
lockOptions = buildLockOptions( lockModeType, properties ); lockOptions = buildLockOptions( lockModeType, properties );
} }
final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph(); final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph();
effectiveEntityGraph.applyConfiguredGraph( properties ); effectiveEntityGraph.applyConfiguredGraph( properties );
loadQueryInfluencers.setReadOnly( getReadOnlyHint( properties ) ); loadQueryInfluencers.setReadOnly( readOnlyHint( properties ) );
return byId( entityClass ) return byId( entityClass )
.with( determineAppropriateLocalCacheMode( properties ) ) .with( determineAppropriateLocalCacheMode( properties ) )
@ -2306,17 +2277,14 @@ public class SessionImpl
.load( primaryKey ); .load( primaryKey );
} }
catch ( EntityNotFoundException enfe ) { catch ( EntityNotFoundException enfe ) {
/* // This may happen if the entity has an associations mapped with
This may happen if the entity has an associations mapped with @NotFound(action = NotFoundAction.EXCEPTION) // @NotFound(action = NotFoundAction.EXCEPTION) and this associated
and this associated entity is not found. // entity is not found
*/
if ( enfe instanceof FetchNotFoundException ) { if ( enfe instanceof FetchNotFoundException ) {
throw enfe; throw enfe;
} }
/* // This may happen if the entity has an associations which is
This may happen if the entity has an associations which is filtered by a FilterDef // filtered by a FilterDef and this associated entity is not found
and this associated entity is not found.
*/
if ( enfe instanceof EntityFilterException ) { if ( enfe instanceof EntityFilterException ) {
throw enfe; throw enfe;
} }
@ -2370,30 +2338,28 @@ public class SessionImpl
CacheRetrieveMode retrieveMode = getCacheRetrieveMode(); CacheRetrieveMode retrieveMode = getCacheRetrieveMode();
LockOptions lockOptions = new LockOptions(); LockOptions lockOptions = new LockOptions();
for ( FindOption option : options ) { for ( FindOption option : options ) {
if ( option instanceof CacheStoreMode ) { if ( option instanceof CacheStoreMode cacheStoreMode ) {
storeMode = (CacheStoreMode) option; storeMode = cacheStoreMode;
} }
else if ( option instanceof CacheRetrieveMode ) { else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) {
retrieveMode = (CacheRetrieveMode) option; retrieveMode = cacheRetrieveMode;
} }
else if ( option instanceof LockModeType ) { else if ( option instanceof LockModeType lockModeType ) {
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( (LockModeType) option ) ); lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
} }
else if ( option instanceof LockMode ) { else if ( option instanceof LockMode lockMode ) {
lockOptions.setLockMode( (LockMode) option ); lockOptions.setLockMode( lockMode );
} }
else if ( option instanceof LockOptions ) { else if ( option instanceof LockOptions lockOpts ) {
lockOptions = (LockOptions) option; lockOptions = lockOpts;
} }
else if ( option instanceof PessimisticLockScope ) { else if ( option instanceof PessimisticLockScope pessimisticLockScope ) {
lockOptions.setLockScope( (PessimisticLockScope) option ); lockOptions.setLockScope( pessimisticLockScope );
} }
else if ( option instanceof Timeout ) { else if ( option instanceof Timeout timeout ) {
final Timeout timeout = (Timeout) option;
lockOptions.setTimeOut( timeout.milliseconds() ); lockOptions.setTimeOut( timeout.milliseconds() );
} }
else if ( option instanceof EnabledFetchProfile ) { else if ( option instanceof EnabledFetchProfile enabledFetchProfile ) {
final EnabledFetchProfile enabledFetchProfile = (EnabledFetchProfile) option;
loadAccess.enableFetchProfile( enabledFetchProfile.profileName() ); loadAccess.enableFetchProfile( enabledFetchProfile.profileName() );
} }
else if ( option instanceof ReadOnlyMode ) { else if ( option instanceof ReadOnlyMode ) {
@ -2413,19 +2379,23 @@ public class SessionImpl
public <T> T find(EntityGraph<T> entityGraph, Object primaryKey, FindOption... options) { public <T> T find(EntityGraph<T> entityGraph, Object primaryKey, FindOption... options) {
final RootGraph<T> graph = (RootGraph<T>) entityGraph; final RootGraph<T> graph = (RootGraph<T>) entityGraph;
final Class<T> entityClass = graph.getGraphedType().getJavaType(); final Class<T> entityClass = graph.getGraphedType().getJavaType();
return loadAccessWithOptions( entityClass, options ) return loadAccessWithOptions( entityClass, options ).withLoadGraph( graph ).load( primaryKey );
.withLoadGraph( graph )
.load( primaryKey );
} }
private void checkTransactionNeededForLock(LockModeType lockModeType) { private void checkTransactionNeededForLock(LockMode lockMode) {
if ( lockModeType != LockModeType.NONE ) { if ( !LockMode.PESSIMISTIC_READ.greaterThan( lockMode ) ) {
checkTransactionNeededForUpdateOperation(); checkTransactionNeededForUpdateOperation();
} }
} }
private static Boolean getReadOnlyHint(Map<String, Object> properties) { private static Boolean readOnlyHint(Map<String, Object> properties) {
return properties == null ? null : (Boolean) properties.get( HINT_READ_ONLY ); if ( properties == null ) {
return null;
}
else {
final Object value = properties.get( HINT_READ_ONLY );
return value == null ? null : ConfigurationHelper.getBoolean( value );
}
} }
protected CacheMode determineAppropriateLocalCacheMode(Map<String, Object> localProperties) { protected CacheMode determineAppropriateLocalCacheMode(Map<String, Object> localProperties) {
@ -2437,24 +2407,26 @@ public class SessionImpl
} }
if ( retrieveMode == null ) { if ( retrieveMode == null ) {
// use the EM setting // use the EM setting
retrieveMode = fastSessionServices.getCacheRetrieveMode( this.properties ); retrieveMode = fastSessionServices.getCacheRetrieveMode( properties );
} }
if ( storeMode == null ) { if ( storeMode == null ) {
// use the EM setting // use the EM setting
storeMode = fastSessionServices.getCacheStoreMode( this.properties ); storeMode = fastSessionServices.getCacheStoreMode( properties );
} }
return interpretCacheMode( storeMode, retrieveMode ); return interpretCacheMode( storeMode, retrieveMode );
} }
private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) { private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); final CacheRetrieveMode cacheRetrieveMode =
(CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE );
return cacheRetrieveMode == null return cacheRetrieveMode == null
? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE ) ? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE )
: cacheRetrieveMode; : cacheRetrieveMode;
} }
private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) { private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE ); final CacheStoreMode cacheStoreMode =
(CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE );
return cacheStoreMode == null return cacheStoreMode == null
? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE ) ? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE )
: cacheStoreMode; : cacheStoreMode;
@ -2496,40 +2468,35 @@ public class SessionImpl
@Override @Override
public void lock(Object entity, LockModeType lockModeType) { public void lock(Object entity, LockModeType lockModeType) {
lock( entity, lockModeType, (Map<String,Object>) null ); lock( entity, LockModeTypeHelper.getLockMode( lockModeType ) );
} }
@Override @Override
public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) { public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
checkOpen(); lock( entity, buildLockOptions( lockModeType, properties ) );
checkTransactionNeededForUpdateOperation();
if ( !contains( entity ) ) {
throw new IllegalArgumentException( "entity not in the persistence context" );
}
final LockOptions lockOptions = buildLockOptions( lockModeType, properties );
try {
fireLock( entity, lockOptions );
}
catch (RuntimeException e) {
throw getExceptionConverter().convert( e, lockOptions );
}
} }
@Override @Override
public void lock(Object entity, LockModeType lockMode, LockOption... options) { public void lock(Object entity, LockModeType lockMode, LockOption... options) {
LockOptions lockOptions = new LockOptions( LockModeTypeHelper.getLockMode(lockMode) ); lock( entity, buildLockOptions( lockMode, options ) );
}
private static LockOptions buildLockOptions(LockModeType lockMode, LockOption[] options) {
final LockOptions lockOptions = new LockOptions( LockModeTypeHelper.getLockMode( lockMode ) );
for ( LockOption option : options ) { for ( LockOption option : options ) {
if ( option instanceof PessimisticLockScope ) { if ( option instanceof PessimisticLockScope lockScope ) {
lockOptions.setLockScope( (PessimisticLockScope) option ); lockOptions.setLockScope( lockScope );
} }
else if ( option instanceof Timeout ) { else if ( option instanceof Timeout timeout ) {
final Timeout timeout = (Timeout) option;
lockOptions.setTimeOut( timeout.milliseconds() ); lockOptions.setTimeOut( timeout.milliseconds() );
} }
} }
lock( entity, lockOptions ); return lockOptions;
}
@Override
public void refresh(Object entity, LockModeType lockModeType) {
refresh( entity, LockModeTypeHelper.getLockMode( lockModeType ) );
} }
@Override @Override
@ -2537,40 +2504,19 @@ public class SessionImpl
refresh( entity, null, properties ); refresh( entity, null, properties );
} }
@Override
public void refresh(Object entity, LockModeType lockModeType) {
refresh( entity, lockModeType, null );
}
@Override @Override
public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) { public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
checkOpen(); checkOpen();
final CacheMode previousCacheMode = getCacheMode(); final CacheMode previousCacheMode = getCacheMode();
final CacheMode refreshCacheMode = determineAppropriateLocalCacheMode( properties ); final CacheMode refreshCacheMode = determineAppropriateLocalCacheMode( properties );
LockOptions lockOptions = null;
try { try {
setCacheMode( refreshCacheMode ); setCacheMode( refreshCacheMode );
if ( lockModeType == null ) {
if ( !contains( entity ) ) {
throw getExceptionConverter().convert( new IllegalArgumentException( "Entity not managed" ) );
}
if ( lockModeType != null ) {
checkTransactionNeededForLock( lockModeType );
lockOptions = buildLockOptions( lockModeType, properties );
refresh( entity, lockOptions );
}
else {
refresh( entity ); refresh( entity );
} }
} else {
catch ( MappingException e ) { refresh( entity, buildLockOptions( lockModeType, properties ) );
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); }
}
catch ( RuntimeException e ) {
throw getExceptionConverter().convert( e, lockOptions );
} }
finally { finally {
setCacheMode( previousCacheMode ); setCacheMode( previousCacheMode );
@ -2582,23 +2528,22 @@ public class SessionImpl
CacheStoreMode storeMode = getCacheStoreMode(); CacheStoreMode storeMode = getCacheStoreMode();
LockOptions lockOptions = new LockOptions(); LockOptions lockOptions = new LockOptions();
for ( RefreshOption option : options ) { for ( RefreshOption option : options ) {
if ( option instanceof CacheStoreMode ) { if ( option instanceof CacheStoreMode cacheStoreMode ) {
storeMode = (CacheStoreMode) option; storeMode = cacheStoreMode;
} }
else if ( option instanceof LockModeType ) { else if ( option instanceof LockModeType lockModeType ) {
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( (LockModeType) option ) ); lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
} }
else if ( option instanceof LockMode ) { else if ( option instanceof LockMode lockMode ) {
lockOptions.setLockMode( (LockMode) option ); lockOptions.setLockMode( lockMode );
} }
else if ( option instanceof LockOptions ) { else if ( option instanceof LockOptions lockOpts ) {
lockOptions = (LockOptions) option; lockOptions = lockOpts;
} }
else if ( option instanceof PessimisticLockScope ) { else if ( option instanceof PessimisticLockScope pessimisticLockScope ) {
lockOptions.setLockScope( (PessimisticLockScope) option ); lockOptions.setLockScope( pessimisticLockScope );
} }
else if ( option instanceof Timeout ) { else if ( option instanceof Timeout timeout ) {
final Timeout timeout = (Timeout) option;
lockOptions.setTimeOut( timeout.milliseconds() ); lockOptions.setTimeOut( timeout.milliseconds() );
} }
} }
@ -2616,7 +2561,7 @@ public class SessionImpl
} }
private LockOptions buildLockOptions(LockModeType lockModeType, Map<String, Object> properties) { private LockOptions buildLockOptions(LockModeType lockModeType, Map<String, Object> properties) {
LockOptions lockOptions = new LockOptions(); final LockOptions lockOptions = new LockOptions();
if ( this.lockOptions != null ) { //otherwise the default LockOptions constructor is the same as DEFAULT_LOCK_OPTIONS if ( this.lockOptions != null ) { //otherwise the default LockOptions constructor is the same as DEFAULT_LOCK_OPTIONS
LockOptions.copy( this.lockOptions, lockOptions ); LockOptions.copy( this.lockOptions, lockOptions );
} }
@ -2725,15 +2670,15 @@ public class SessionImpl
break; break;
case USE_SUBSELECT_FETCH: case USE_SUBSELECT_FETCH:
case HINT_ENABLE_SUBSELECT_FETCH: case HINT_ENABLE_SUBSELECT_FETCH:
setSubselectFetchingEnabled( Boolean.parseBoolean( value.toString() ) ); setSubselectFetchingEnabled( parseBoolean( value.toString() ) );
break; break;
case DEFAULT_BATCH_FETCH_SIZE: case DEFAULT_BATCH_FETCH_SIZE:
case HINT_BATCH_FETCH_SIZE: case HINT_BATCH_FETCH_SIZE:
setFetchBatchSize( Integer.parseInt( value.toString() ) ); setFetchBatchSize( parseInt( value.toString() ) );
break; break;
case STATEMENT_BATCH_SIZE: case STATEMENT_BATCH_SIZE:
case HINT_JDBC_BATCH_SIZE: case HINT_JDBC_BATCH_SIZE:
setJdbcBatchSize( Integer.parseInt( value.toString() ) ); setJdbcBatchSize( parseInt( value.toString() ) );
break; break;
} }
} }
@ -2758,9 +2703,9 @@ public class SessionImpl
public ProcedureCall createNamedStoredProcedureQuery(String name) { public ProcedureCall createNamedStoredProcedureQuery(String name) {
checkOpen(); checkOpen();
try { try {
final NamedCallableQueryMemento memento = getFactory().getQueryEngine() final NamedCallableQueryMemento memento =
.getNamedObjectRepository() getFactory().getQueryEngine().getNamedObjectRepository()
.getCallableQueryMemento( name ); .getCallableQueryMemento( name );
if ( memento == null ) { if ( memento == null ) {
throw new IllegalArgumentException( "No @NamedStoredProcedureQuery was found with that name : " + name ); throw new IllegalArgumentException( "No @NamedStoredProcedureQuery was found with that name : " + name );
} }

View File

@ -20,8 +20,9 @@ import org.hibernate.FlushMode;
* @author Emmanuel Bernard * @author Emmanuel Bernard
*/ */
public abstract class ConfigurationHelper { public abstract class ConfigurationHelper {
public static void overrideProperties(Properties properties, Map<?,?> overrides) { public static void overrideProperties(Properties properties, Map<?,?> overrides) {
for ( Map.Entry entry : overrides.entrySet() ) { for ( Map.Entry<?,?> entry : overrides.entrySet() ) {
if ( entry.getKey() != null && entry.getValue() != null ) { if ( entry.getKey() != null && entry.getValue() != null ) {
properties.put( entry.getKey(), entry.getValue() ); properties.put( entry.getKey(), entry.getValue() );
} }
@ -29,25 +30,21 @@ public abstract class ConfigurationHelper {
} }
public static FlushMode getFlushMode(Object value, FlushMode defaultFlushMode) { public static FlushMode getFlushMode(Object value, FlushMode defaultFlushMode) {
final FlushMode flushMode; if ( value instanceof FlushMode mode ) {
if ( value instanceof FlushMode ) { return mode;
flushMode = (FlushMode) value;
} }
else if ( value instanceof jakarta.persistence.FlushModeType ) { else if ( value instanceof jakarta.persistence.FlushModeType flushModeType ) {
flushMode = ConfigurationHelper.getFlushMode( (jakarta.persistence.FlushModeType) value ); return getFlushMode( flushModeType );
} }
else if ( value instanceof String ) { else if ( value instanceof String string ) {
flushMode = ConfigurationHelper.getFlushMode( (String) value ); return getFlushMode( string );
} }
else { else {
flushMode = defaultFlushMode; if ( defaultFlushMode == null ) {
throw new PersistenceException( "Unable to parse org.hibernate.flushMode: " + value );
}
return defaultFlushMode;
} }
if ( flushMode == null ) {
throw new PersistenceException( "Unable to parse org.hibernate.flushMode: " + value );
}
return flushMode;
} }
public static FlushMode getFlushMode(Object value) { public static FlushMode getFlushMode(Object value) {
@ -55,11 +52,7 @@ public abstract class ConfigurationHelper {
} }
private static FlushMode getFlushMode(String flushMode) { private static FlushMode getFlushMode(String flushMode) {
if ( flushMode == null ) { return flushMode == null ? null : FlushMode.valueOf( flushMode.toUpperCase(Locale.ROOT) );
return null;
}
flushMode = flushMode.toUpperCase( Locale.ROOT );
return FlushMode.valueOf( flushMode );
} }
private static FlushMode getFlushMode(FlushModeType flushMode) { private static FlushMode getFlushMode(FlushModeType flushMode) {
@ -74,29 +67,38 @@ public abstract class ConfigurationHelper {
} }
public static Integer getInteger(Object value) { public static Integer getInteger(Object value) {
if ( value instanceof Integer ) { if ( value instanceof Integer integer ) {
return (Integer) value; return integer;
}
else if ( value instanceof String string ) {
return Integer.valueOf( string );
} }
else { else {
return Integer.valueOf( (String) value ); throw new IllegalArgumentException( "value must be a string or integer: " + value );
} }
} }
public static Boolean getBoolean(Object value) { public static Boolean getBoolean(Object value) {
if ( value instanceof Boolean ) { if ( value instanceof Boolean bool ) {
return (Boolean) value; return bool;
}
else if ( value instanceof String string ) {
return Boolean.valueOf( string );
} }
else { else {
return Boolean.valueOf( (String) value ); throw new IllegalArgumentException( "value must be a string or boolean: " + value );
} }
} }
public static CacheMode getCacheMode(Object value) { public static CacheMode getCacheMode(Object value) {
if ( value instanceof CacheMode ) { if ( value instanceof CacheMode cacheMode ) {
return (CacheMode) value; return cacheMode;
}
else if ( value instanceof String string ) {
return CacheMode.valueOf( string );
} }
else { else {
return CacheMode.valueOf( (String) value ); throw new IllegalArgumentException( "value must be a string or CacheMode: " + value );
} }
} }
} }

View File

@ -50,8 +50,9 @@ public class FlushAndTransactionTest extends BaseEntityManagerFunctionalTestCase
catch (TransactionRequiredException e) { catch (TransactionRequiredException e) {
//success //success
} }
em.lock( book, LockModeType.READ );
try { try {
em.lock( book, LockModeType.READ ); em.lock( book, LockModeType.PESSIMISTIC_READ );
fail( "lock has to be inside a Tx" ); fail( "lock has to be inside a Tx" );
} }
catch (TransactionRequiredException e) { catch (TransactionRequiredException e) {