All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.internal.SessionImpl Maven / Gradle / Ivy

There is a newer version: 6.6.2.Final
Show newest version
/*
 * 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 .
 */
package org.hibernate.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.hibernate.CacheMode;
import org.hibernate.ConnectionAcquisitionMode;
import org.hibernate.FetchNotFoundException;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.LobHelper;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.MultiIdentifierLoadAccess;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.NaturalIdMultiLoadAccess;
import org.hibernate.ObjectDeletedException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionException;
import org.hibernate.SharedSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.Transaction;
import org.hibernate.TransientObjectException;
import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.binder.internal.TenantIdBinder;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.NonContextualLobCreator;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.EffectiveEntityGraph;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
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.EventManager;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.ClearEvent;
import org.hibernate.event.spi.ClearEventListener;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.DirtyCheckEvent;
import org.hibernate.event.spi.DirtyCheckEventListener;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EvictEvent;
import org.hibernate.event.spi.EvictEventListener;
import org.hibernate.event.spi.FlushEvent;
import org.hibernate.event.spi.FlushEventListener;
import org.hibernate.event.spi.InitializeCollectionEvent;
import org.hibernate.event.spi.InitializeCollectionEventListener;
import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.event.spi.LoadEventListener.LoadType;
import org.hibernate.event.spi.LockEvent;
import org.hibernate.event.spi.LockEventListener;
import org.hibernate.event.spi.MergeContext;
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;
import org.hibernate.event.spi.ReplicateEventListener;
import org.hibernate.event.spi.ResolveNaturalIdEvent;
import org.hibernate.event.spi.ResolveNaturalIdEventListener;
import org.hibernate.event.spi.SaveOrUpdateEvent;
import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jpa.internal.LegacySpecHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.loader.internal.IdentifierLoadAccessImpl;
import org.hibernate.loader.internal.LoadAccessContext;
import org.hibernate.loader.internal.NaturalIdLoadAccessImpl;
import org.hibernate.loader.internal.SimpleNaturalIdLoadAccessImpl;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.Query;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.UnknownSqlResultSetMappingException;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.internal.SessionStatisticsImpl;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.descriptor.WrapperOptions;

import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.LockModeType;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.TransactionRequiredException;
import jakarta.persistence.metamodel.Metamodel;

import static java.lang.Boolean.parseBoolean;
import static java.lang.System.currentTimeMillis;
import static java.util.Collections.unmodifiableMap;
import static org.hibernate.CacheMode.fromJpaModes;
import static org.hibernate.cfg.AvailableSettings.CRITERIA_COPY_TREE;
import static org.hibernate.cfg.AvailableSettings.DEFAULT_BATCH_FETCH_SIZE;
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_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
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_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE;
import static org.hibernate.cfg.AvailableSettings.USE_SUBSELECT_FETCH;
import static org.hibernate.event.spi.LoadEventListener.IMMEDIATE_LOAD;
import static org.hibernate.event.spi.LoadEventListener.INTERNAL_LOAD_EAGER;
import static org.hibernate.event.spi.LoadEventListener.INTERNAL_LOAD_LAZY;
import static org.hibernate.event.spi.LoadEventListener.INTERNAL_LOAD_NULLABLE;
import static org.hibernate.jpa.HibernateHints.HINT_BATCH_FETCH_SIZE;
import static org.hibernate.jpa.HibernateHints.HINT_ENABLE_SUBSELECT_FETCH;
import static org.hibernate.jpa.HibernateHints.HINT_FETCH_PROFILE;
import static org.hibernate.jpa.HibernateHints.HINT_JDBC_BATCH_SIZE;
import static org.hibernate.jpa.HibernateHints.HINT_READ_ONLY;
import static org.hibernate.jpa.HibernateHints.HINT_FLUSH_MODE;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_LOCK_TIMEOUT;
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_QUERY_TIMEOUT;
import static org.hibernate.jpa.internal.util.CacheModeHelper.interpretCacheMode;
import static org.hibernate.jpa.internal.util.LockOptionsHelper.applyPropertiesToLockOptions;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;

/**
 * Concrete implementation of the {@link Session} API.
 * 

* Exposes two interfaces: *

    *
  • {@link Session} to the application, and *
  • {@link SessionImplementor} and {@link EventSource} (both SPI interfaces) to other subsystems. *
*

* This class is not thread-safe. * * @author Gavin King * @author Steve Ebersole * @author Brett Meyer * @author Chris Cranford * @author Sanne Grinovero */ public class SessionImpl extends AbstractSharedSessionContract implements Serializable, SharedSessionContractImplementor, JdbcSessionOwner, SessionImplementor, EventSource, TransactionCoordinatorBuilder.Options, WrapperOptions, LoadAccessContext { private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( SessionImpl.class ); // Defaults to null which means the properties are the default // as defined in FastSessionServices#defaultSessionProperties private Map properties; private transient ActionQueue actionQueue; private transient StatefulPersistenceContext persistenceContext; private transient LoadQueryInfluencers loadQueryInfluencers; private LockOptions lockOptions; private boolean autoClear; private final boolean autoClose; private transient LoadEvent loadEvent; //cached LoadEvent instance private transient TransactionObserver transactionObserver; // TODO: this is unused and can be removed private transient boolean isEnforcingFetchGraph; public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); final HibernateMonitoringEvent sessionOpenEvent = getEventManager().beginSessionOpenEvent(); persistenceContext = createPersistenceContext(); actionQueue = createActionQueue(); autoClear = options.shouldAutoClear(); autoClose = options.shouldAutoClose(); if ( options instanceof SharedSessionCreationOptions ) { final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options; final ActionQueue.TransactionCompletionProcesses transactionCompletionProcesses = sharedOptions.getTransactionCompletionProcesses(); if ( sharedOptions.isTransactionCoordinatorShared() && transactionCompletionProcesses != null ) { actionQueue.setTransactionCompletionProcesses( transactionCompletionProcesses, true ); } } loadQueryInfluencers = new LoadQueryInfluencers( factory, options ); final StatisticsImplementor statistics = factory.getStatistics(); if ( statistics.isStatisticsEnabled() ) { statistics.openSession(); } if ( properties != null ) { //There might be custom properties for this session that affect the LockOptions state applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); } 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 ); if ( log.isTraceEnabled() ) { log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() ); } getEventManager().completeSessionOpenEvent( sessionOpenEvent, this ); } private FlushMode getInitialFlushMode() { return properties == null ? fastSessionServices.initialSessionFlushMode : ConfigurationHelper.getFlushMode( getSessionProperty( HINT_FLUSH_MODE ), FlushMode.AUTO ); } private void setUpMultitenancy(SessionFactoryImplementor factory) { if ( factory.getDefinedFilterNames().contains( TenantIdBinder.FILTER_NAME ) ) { final Object tenantIdentifier = getTenantIdentifierValue(); if ( tenantIdentifier == null ) { throw new HibernateException( "SessionFactory configured for multi-tenancy, but no tenant identifier specified" ); } else { final CurrentTenantIdentifierResolver resolver = factory.getCurrentTenantIdentifierResolver(); if ( resolver==null || !resolver.isRoot( tenantIdentifier ) ) { // turn on the filter, unless this is the "root" tenant with access to all partitions loadQueryInfluencers .enableFilter( TenantIdBinder.FILTER_NAME ) .setParameter( TenantIdBinder.PARAMETER_NAME, tenantIdentifier ); } } } } protected StatefulPersistenceContext createPersistenceContext() { return new StatefulPersistenceContext( this ); } protected ActionQueue createActionQueue() { return new ActionQueue( this ); } private LockOptions getLockOptionsForRead() { return this.lockOptions == null ? fastSessionServices.defaultLockOptions : this.lockOptions; } private LockOptions getLockOptionsForWrite() { if ( this.lockOptions == null ) { this.lockOptions = new LockOptions(); } return this.lockOptions; } protected void applyQuerySettingsAndHints(SelectionQuery query) { applyLockOptionsHint( query ); } protected void applyLockOptionsHint(SelectionQuery query) { final LockOptions lockOptionsForRead = getLockOptionsForRead(); if ( lockOptionsForRead.getLockMode() != LockMode.NONE ) { query.setLockMode( getLockMode( lockOptionsForRead.getLockMode() ) ); } final Object specQueryTimeout = LegacySpecHelper.getInteger( HINT_SPEC_QUERY_TIMEOUT, HINT_JAVAEE_QUERY_TIMEOUT, this::getSessionProperty ); if ( specQueryTimeout != null ) { query.setHint( HINT_SPEC_QUERY_TIMEOUT, specQueryTimeout ); } } protected void applyQuerySettingsAndHints(Query query) { applyQuerySettingsAndHints( (SelectionQuery) query ); final Integer specLockTimeout = LegacySpecHelper.getInteger( HINT_SPEC_LOCK_TIMEOUT, HINT_JAVAEE_LOCK_TIMEOUT, this::getSessionProperty, // treat WAIT_FOREVER the same as null (value) -> !Integer.valueOf( LockOptions.WAIT_FOREVER ).equals( value ) ); if ( specLockTimeout != null ) { query.setHint( HINT_SPEC_LOCK_TIMEOUT, specLockTimeout ); } } private Object getSessionProperty(final String name) { if ( properties == null ) { return fastSessionServices.defaultSessionProperties.get( name ); } else { return properties.get( name ); } } @Override public SharedSessionBuilder sessionWithOptions() { return new SharedSessionBuilderImpl( this ); } @Override public void clear() { checkOpen(); // Do not call checkTransactionSynchStatus() here -- if a delayed // afterCompletion exists, it can cause an infinite loop. pulseTransactionCoordinator(); try { internalClear(); } catch (RuntimeException e) { throw getExceptionConverter().convert( e ); } } private void internalClear() { persistenceContext.clear(); actionQueue.clear(); fastSessionServices.eventListenerGroup_CLEAR .fireLazyEventOnEachListener( this::createClearEvent, ClearEventListener::onClear ); } private ClearEvent createClearEvent() { return new ClearEvent( this ); } @Override public void close() throws HibernateException { if ( isClosed() ) { if ( getFactory().getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) { throw new IllegalStateException( "Illegal call to #close() on already closed Session/EntityManager" ); } log.trace( "Already closed" ); return; } closeWithoutOpenChecks(); } public void closeWithoutOpenChecks() throws HibernateException { if ( log.isTraceEnabled() ) { log.tracef( "Closing session [%s]", getSessionIdentifier() ); } final EventManager eventManager = getEventManager(); final HibernateMonitoringEvent sessionClosedEvent = eventManager.beginSessionClosedEvent(); // todo : we want this check if usage is JPA, but not native Hibernate usage final SessionFactoryImplementor sessionFactory = getSessionFactory(); if ( sessionFactory.getSessionFactoryOptions().isJpaBootstrap() ) { // Original hibernate-entitymanager EM#close behavior checkSessionFactoryOpen(); checkOpenOrWaitingForAutoClose(); if ( fastSessionServices.discardOnClose || !isTransactionInProgressAndNotMarkedForRollback() ) { super.close(); } else { //Otherwise, session auto-close will be enabled by shouldAutoCloseSession(). prepareForAutoClose(); } } else { super.close(); } final StatisticsImplementor statistics = sessionFactory.getStatistics(); if ( statistics.isStatisticsEnabled() ) { statistics.closeSession(); } eventManager.completeSessionClosedEvent( sessionClosedEvent, this ); } private boolean isTransactionInProgressAndNotMarkedForRollback() { if ( waitingForAutoClose ) { return getSessionFactory().isOpen() && getTransactionCoordinator().isTransactionActive( false ); } else { return !isClosed() && getTransactionCoordinator().isTransactionActive( false ); } } @Override protected boolean shouldCloseJdbcCoordinatorOnClose(boolean isTransactionCoordinatorShared) { if ( !isTransactionCoordinatorShared ) { return super.shouldCloseJdbcCoordinatorOnClose( isTransactionCoordinatorShared ); } final ActionQueue actionQueue = getActionQueue(); if ( actionQueue.hasBeforeTransactionActions() || actionQueue.hasAfterTransactionActions() ) { log.warn( "On close, shared Session had before/after transaction actions that have not yet been processed" ); } return false; } @Override public boolean isAutoCloseSessionEnabled() { return autoClose; } @Override public boolean isOpen() { checkSessionFactoryOpen(); checkTransactionSynchStatus(); try { return !isClosed(); } catch (HibernateException he) { throw getExceptionConverter().convert( he ); } } protected void checkSessionFactoryOpen() { if ( !getFactory().isOpen() ) { log.debug( "Forcing Session/EntityManager closed as SessionFactory/EntityManagerFactory has been closed" ); setClosed(); } } private void managedFlush() { if ( isClosed() && !waitingForAutoClose ) { log.trace( "Skipping auto-flush due to session closed" ); return; } log.trace( "Automatically flushing session" ); doFlush(); } @Override public boolean shouldAutoClose() { if ( waitingForAutoClose ) { return true; } else if ( isClosed() ) { return false; } else { // JPA technically requires that this be a PersistentUnityTransactionType#JTA to work, // but we do not assert that here... //return isAutoCloseSessionEnabled() && getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta(); return isAutoCloseSessionEnabled(); } } private void managedClose() { log.trace( "Automatically closing session" ); closeWithoutOpenChecks(); } @Override public void setAutoClear(boolean enabled) { checkOpenOrWaitingForAutoClose(); autoClear = enabled; } public void afterOperation(boolean success) { if ( !isTransactionInProgress() ) { getJdbcCoordinator().afterTransaction(); } } @Override public void addEventListeners(SessionEventListener... listeners) { getEventListenerManager().addListener( listeners ); } /** * clear all the internal collections, just * to help the garbage collector, does not * clear anything that is needed during the * afterTransactionCompletion() phase */ @Override protected void cleanupOnClose() { persistenceContext.clear(); } @Override public LockMode getCurrentLockMode(Object object) throws HibernateException { checkOpen(); checkTransactionSynchStatus(); if ( object == null ) { throw new NullPointerException( "null object passed to getCurrentLockMode()" ); } final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { object = lazyInitializer.getImplementation( this ); if ( object == null ) { return LockMode.NONE; } } final EntityEntry e = persistenceContext.getEntry( object ); if ( e == null ) { throw new TransientObjectException( "Given object not associated with the session" ); } if ( e.getStatus() != Status.MANAGED ) { throw new ObjectDeletedException( "The given object was deleted", e.getId(), e.getPersister().getEntityName() ); } return e.getLockMode(); } @Override public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException { checkOpenOrWaitingForAutoClose(); // todo : should this get moved to PersistentContext? // logically, is PersistentContext the "thing" to which an interceptor gets attached? final Object result = persistenceContext.getEntity( key ); if ( result == null ) { final Object newObject = getInterceptor().getEntity( key.getEntityName(), key.getIdentifier() ); if ( newObject != null ) { lock( newObject, LockMode.NONE ); } return newObject; } else { return result; } } protected void checkNoUnresolvedActionsBeforeOperation() { if ( persistenceContext.getCascadeLevel() == 0 && actionQueue.hasUnresolvedEntityInsertActions() ) { throw new IllegalStateException( "There are delayed insert actions before operation as cascade level 0." ); } } protected void checkNoUnresolvedActionsAfterOperation() { if ( persistenceContext.getCascadeLevel() == 0 ) { actionQueue.checkNoUnresolvedActionsAfterOperation(); } delayedAfterCompletion(); } @Override public void delayedAfterCompletion() { TransactionCoordinator coordinator = getTransactionCoordinator(); if ( coordinator instanceof JtaTransactionCoordinatorImpl ) { ( (JtaTransactionCoordinatorImpl) coordinator).getSynchronizationCallbackCoordinator() .processAnyDelayedAfterCompletion(); } } @Override public void pulseTransactionCoordinator() { super.pulseTransactionCoordinator(); } @Override public void checkOpenOrWaitingForAutoClose() { super.checkOpenOrWaitingForAutoClose(); } // saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override @Deprecated public void saveOrUpdate(Object object) throws HibernateException { saveOrUpdate( null, object ); } @Override @Deprecated public void saveOrUpdate(String entityName, Object obj) throws HibernateException { fireSaveOrUpdate( new SaveOrUpdateEvent( entityName, obj, this ) ); } private void fireSaveOrUpdate(final SaveOrUpdateEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); fastSessionServices.eventListenerGroup_SAVE_UPDATE .fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate ); checkNoUnresolvedActionsAfterOperation(); } // save() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override @Deprecated public Object save(Object obj) throws HibernateException { return save( null, obj ); } @Override @Deprecated public Object save(String entityName, Object object) throws HibernateException { return fireSave( new SaveOrUpdateEvent( entityName, object, this ) ); } private Object fireSave(final SaveOrUpdateEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); fastSessionServices.eventListenerGroup_SAVE .fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate ); checkNoUnresolvedActionsAfterOperation(); return event.getResultId(); } // update() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override @Deprecated public void update(Object obj) throws HibernateException { update( null, obj ); } @Override @Deprecated public void update(String entityName, Object object) throws HibernateException { fireUpdate( new SaveOrUpdateEvent( entityName, object, this ) ); } private void fireUpdate(SaveOrUpdateEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); fastSessionServices.eventListenerGroup_UPDATE .fireEventOnEachListener( event, SaveOrUpdateEventListener::onSaveOrUpdate ); checkNoUnresolvedActionsAfterOperation(); } // lock() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void lock(Object object, LockOptions lockOptions) { fireLock( new LockEvent( object, lockOptions, this ) ); } @Override public void lock(String entityName, Object object, LockOptions lockOptions) { fireLock( new LockEvent( entityName, object, lockOptions, this ) ); } @Override public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException { fireLock( new LockEvent( entityName, object, lockMode, this ) ); } @Override @Deprecated public LockRequest buildLockRequest(LockOptions lockOptions) { return new LockRequestImpl( lockOptions ); } @Override public void lock(Object object, LockMode lockMode) throws HibernateException { fireLock( new LockEvent( object, lockMode, this ) ); } private void fireLock(String entityName, Object object, LockOptions options) { fireLock( new LockEvent( entityName, object, options, this ) ); } private void fireLock(Object object, LockOptions options) { fireLock( new LockEvent( object, options, this ) ); } private void fireLock(LockEvent event) { checkOpen(); pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_LOCK .fireEventOnEachListener( event, LockEventListener::onLock ); delayedAfterCompletion(); } // persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void persist(String entityName, Object object) throws HibernateException { checkOpen(); firePersist( new PersistEvent( entityName, object, this ) ); } @Override public void persist(Object object) throws HibernateException { checkOpen(); firePersist( new PersistEvent( null, object, this ) ); } @Override public void persist(String entityName, Object object, PersistContext copiedAlready) throws HibernateException { checkOpenOrWaitingForAutoClose(); firePersist( copiedAlready, new PersistEvent( entityName, object, this ) ); } private void firePersist(final PersistEvent event) { Throwable originalException = null; try { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); fastSessionServices.eventListenerGroup_PERSIST .fireEventOnEachListener( event, PersistEventListener::onPersist ); } catch (MappingException e) { originalException = getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch (RuntimeException e) { originalException = getExceptionConverter().convert( e ); } catch (Throwable t1) { originalException = t1; } finally { Throwable suppressed = null; try { checkNoUnresolvedActionsAfterOperation(); } catch (RuntimeException e) { suppressed = getExceptionConverter().convert( e ); } catch (Throwable t2) { suppressed = t2; } if ( suppressed != null ) { if ( originalException == null ) { originalException = suppressed; } else { originalException.addSuppressed( suppressed ); } } } if ( originalException != null ) { ExceptionHelper.doThrow( originalException ); } } private void firePersist(final PersistContext copiedAlready, final PersistEvent event) { pulseTransactionCoordinator(); try { //Uses a capturing lambda in this case as we need to carry the additional Map parameter: fastSessionServices.eventListenerGroup_PERSIST .fireEventOnEachListener( event, copiedAlready, PersistEventListener::onPersist ); } catch ( MappingException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage() ) ) ; } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } finally { delayedAfterCompletion(); } } // persistOnFlush() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override 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 ); delayedAfterCompletion(); } // merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override @SuppressWarnings("unchecked") public T merge(String entityName, T object) throws HibernateException { checkOpen(); return (T) fireMerge( new MergeEvent( entityName, object, this ) ); } @Override @SuppressWarnings("unchecked") public T merge(T object) throws HibernateException { checkOpen(); return (T) fireMerge( new MergeEvent( null, object, this )); } @Override public void merge(String entityName, Object object, MergeContext copiedAlready) throws HibernateException { checkOpenOrWaitingForAutoClose(); fireMerge( copiedAlready, new MergeEvent( entityName, object, this ) ); } private Object fireMerge(MergeEvent event) { try { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); fastSessionServices.eventListenerGroup_MERGE .fireEventOnEachListener( event, MergeEventListener::onMerge ); checkNoUnresolvedActionsAfterOperation(); } catch ( ObjectDeletedException sse ) { throw getExceptionConverter().convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw getExceptionConverter().convert( e ); } return event.getResult(); } private void fireMerge(final MergeContext mergeContext, final MergeEvent event) { try { pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_MERGE .fireEventOnEachListener( event, mergeContext, MergeEventListener::onMerge ); } catch ( ObjectDeletedException sse ) { throw getExceptionConverter().convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw getExceptionConverter().convert( e ); } finally { delayedAfterCompletion(); } } // delete() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override @Deprecated public void delete(Object object) throws HibernateException { checkOpen(); fireDelete( new DeleteEvent( object, this ) ); } @Override @Deprecated public void delete(String entityName, Object object) throws HibernateException { checkOpen(); fireDelete( new DeleteEvent( entityName, object, this ) ); } @Override public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, DeleteContext transientEntities) throws HibernateException { checkOpenOrWaitingForAutoClose(); final boolean removingOrphanBeforeUpates = persistenceContext.isRemovingOrphanBeforeUpates(); final boolean traceEnabled = log.isTraceEnabled(); if ( traceEnabled && removingOrphanBeforeUpates ) { logRemoveOrphanBeforeUpdates( "before continuing", entityName, object ); } fireDelete( new DeleteEvent( entityName, object, isCascadeDeleteEnabled, removingOrphanBeforeUpates, this ), transientEntities ); if ( traceEnabled && removingOrphanBeforeUpates ) { logRemoveOrphanBeforeUpdates( "after continuing", entityName, object ); } } @Override public void removeOrphanBeforeUpdates(String entityName, Object child) { // TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task // ordering is improved. final boolean traceEnabled = log.isTraceEnabled(); if ( traceEnabled ) { logRemoveOrphanBeforeUpdates( "begin", entityName, child ); } persistenceContext.beginRemoveOrphanBeforeUpdates(); try { checkOpenOrWaitingForAutoClose(); fireDelete( new DeleteEvent( entityName, child, false, true, this ) ); } finally { persistenceContext.endRemoveOrphanBeforeUpdates(); if ( traceEnabled ) { logRemoveOrphanBeforeUpdates( "end", entityName, child ); } } } private void logRemoveOrphanBeforeUpdates(String timing, String entityName, Object entity) { if ( log.isTraceEnabled() ) { final EntityEntry entityEntry = persistenceContext.getEntry( entity ); log.tracef( "%s remove orphan before updates: [%s]", timing, entityEntry == null ? entityName : MessageHelper.infoString( entityName, entityEntry.getId() ) ); } } private void fireDelete(final DeleteEvent event) { try{ pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_DELETE .fireEventOnEachListener( event, DeleteEventListener::onDelete ); } catch ( ObjectDeletedException sse ) { throw getExceptionConverter().convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw getExceptionConverter().convert( e ); } finally { delayedAfterCompletion(); } } private void fireDelete(final DeleteEvent event, final DeleteContext transientEntities) { try{ pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_DELETE .fireEventOnEachListener( event, transientEntities, DeleteEventListener::onDelete ); } catch ( ObjectDeletedException sse ) { throw getExceptionConverter().convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw getExceptionConverter().convert( e ); } finally { delayedAfterCompletion(); } } // load()/get() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void load(Object object, Object id) throws HibernateException { fireLoad( new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() ), LoadEventListener.RELOAD ); } @Override @Deprecated public T load(Class entityClass, Object id) throws HibernateException { return this.byId( entityClass ).getReference( id ); } @Override @Deprecated public Object load(String entityName, Object id) throws HibernateException { return this.byId( entityName ).getReference( id ); } @Override public T get(Class entityClass, Object id) throws HibernateException { return this.byId( entityClass ).load( id ); } @Override public Object get(String entityName, Object id) throws HibernateException { return this.byId( entityName ).load( id ); } /** * Load the data for the object with the specified id into a newly created object. * This is only called when lazily initializing a proxy. * Do NOT return a proxy. */ @Override public Object immediateLoad(String entityName, Object id) throws HibernateException { if ( log.isDebugEnabled() ) { final EntityPersister persister = getFactory().getMappingMetamodel() .getEntityDescriptor( entityName ); log.debugf( "Initializing proxy: %s", MessageHelper.infoString( persister, id, getFactory() ) ); } LoadEvent event = loadEvent; loadEvent = null; event = recycleEventInstance( event, id, entityName ); fireLoadNoChecks( event, IMMEDIATE_LOAD ); final Object result = event.getResult(); finishWithEventInstance( event ); final LazyInitializer lazyInitializer = extractLazyInitializer( result ); return lazyInitializer != null ? lazyInitializer.getImplementation() : result; } @Override public Object internalLoad(String entityName, Object id, boolean eager, boolean nullable) { final LoadType type = internalLoadType( eager, nullable ); final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph(); final GraphSemantic semantic = effectiveEntityGraph.getSemantic(); final RootGraphImplementor graph = effectiveEntityGraph.getGraph(); boolean clearedEffectiveGraph; if ( semantic == null || graph.appliesTo( getFactory().getJpaMetamodel().entity( entityName ) ) ) { clearedEffectiveGraph = false; } else { log.debug("Clearing effective entity graph for subsequent-select"); clearedEffectiveGraph = true; effectiveEntityGraph.clear(); } try { LoadEvent event = loadEvent; loadEvent = null; event = recycleEventInstance( event, id, entityName ); fireLoadNoChecks( event, type ); final Object result = event.getResult(); if ( !nullable ) { UnresolvableObjectException.throwIfNull( result, id, entityName ); } finishWithEventInstance( event ); return result; } finally { if ( clearedEffectiveGraph ) { effectiveEntityGraph.applyGraph( graph, semantic ); } } } protected static LoadType internalLoadType(boolean eager, boolean nullable) { if ( nullable ) { return INTERNAL_LOAD_NULLABLE; } else { return eager ? INTERNAL_LOAD_EAGER : INTERNAL_LOAD_LAZY; } } /** * Helper to avoid creating many new instances of LoadEvent: it's an allocation hot spot. */ private LoadEvent recycleEventInstance(final LoadEvent event, final Object id, final String entityName) { if ( event == null ) { return new LoadEvent( id, entityName, true, this, getReadOnlyFromLoadQueryInfluencers() ); } else { event.setEntityClassName( entityName ); event.setEntityId( id ); event.setInstanceToLoad( null ); return event; } } private void finishWithEventInstance(LoadEvent event) { if ( loadEvent == null ) { event.setEntityClassName( null ); event.setEntityId( null ); event.setInstanceToLoad( null ); event.setResult( null ); loadEvent = event; } } @Override @Deprecated public T load(Class entityClass, Object id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).getReference( id ); } @Override @Deprecated public T load(Class entityClass, Object id, LockOptions lockOptions) throws HibernateException { return this.byId( entityClass ).with( lockOptions ).getReference( id ); } @Override @Deprecated public Object load(String entityName, Object id, LockMode lockMode) throws HibernateException { return this.byId( entityName ).with( new LockOptions( lockMode ) ).getReference( id ); } @Override @Deprecated public Object load(String entityName, Object id, LockOptions lockOptions) throws HibernateException { return this.byId( entityName ).with( lockOptions ).getReference( id ); } @Override public T get(Class entityClass, Object id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).load( id ); } @Override public T get(Class entityClass, Object id, LockOptions lockOptions) throws HibernateException { return this.byId( entityClass ).with( lockOptions ).load( id ); } @Override public Object get(String entityName, Object id, LockMode lockMode) throws HibernateException { return this.byId( entityName ).with( new LockOptions( lockMode ) ).load( id ); } @Override public Object get(String entityName, Object id, LockOptions lockOptions) throws HibernateException { return this.byId( entityName ).with( lockOptions ).load( id ); } @Override public IdentifierLoadAccessImpl byId(String entityName) { return new IdentifierLoadAccessImpl<>( this, requireEntityPersister( entityName ) ); } @Override public IdentifierLoadAccessImpl byId(Class entityClass) { return new IdentifierLoadAccessImpl<>( this, requireEntityPersister( entityClass ) ); } @Override public MultiIdentifierLoadAccess byMultipleIds(Class entityClass) { return new MultiIdentifierLoadAccessImpl<>( this, requireEntityPersister( entityClass ) ); } @Override public MultiIdentifierLoadAccess byMultipleIds(String entityName) { return new MultiIdentifierLoadAccessImpl<>( this, requireEntityPersister( entityName ) ); } @Override public NaturalIdLoadAccess byNaturalId(String entityName) { return new NaturalIdLoadAccessImpl<>( this, requireEntityPersister( entityName ) ); } @Override public NaturalIdLoadAccess byNaturalId(Class entityClass) { return new NaturalIdLoadAccessImpl<>( this, requireEntityPersister( entityClass ) ); } @Override public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName) { return new SimpleNaturalIdLoadAccessImpl<>( this, requireEntityPersister( entityName ) ); } @Override public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass) { return new SimpleNaturalIdLoadAccessImpl<>( this, requireEntityPersister( entityClass ) ); } @Override public NaturalIdMultiLoadAccess byMultipleNaturalId(Class entityClass) { return new NaturalIdMultiLoadAccessStandard<>( requireEntityPersister( entityClass ), this ); } @Override public NaturalIdMultiLoadAccess byMultipleNaturalId(String entityName) { return new NaturalIdMultiLoadAccessStandard<>( requireEntityPersister( entityName ), this ); } @Override public void fireLoad(LoadEvent event, LoadType loadType) { checkOpenOrWaitingForAutoClose(); fireLoadNoChecks( event, loadType ); delayedAfterCompletion(); } //Performance note: // This version of #fireLoad is meant to be invoked by internal methods only, // so to skip the session open, transaction synch, etc.. checks, // which have been proven to be not particularly cheap: // 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 ); } private void fireResolveNaturalId(final ResolveNaturalIdEvent event) { checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_RESOLVE_NATURAL_ID .fireEventOnEachListener( event, ResolveNaturalIdEventListener::onResolveNaturalId ); delayedAfterCompletion(); } // refresh() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void refresh(Object object) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( null, object, this ) ); } @Override @Deprecated public void refresh(String entityName, Object object) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( entityName, object, this ) ); } @Override public void refresh(Object object, LockMode lockMode) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( object, lockMode, this ) ); } @Override public void refresh(Object object, LockOptions lockOptions) throws HibernateException { checkOpen(); refresh( null, object, lockOptions ); } @Override @Deprecated public void refresh(String entityName, Object object, LockOptions lockOptions) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( entityName, object, lockOptions, this ) ); } @Override public void refresh(String entityName, Object object, RefreshContext refreshedAlready) throws HibernateException { checkOpenOrWaitingForAutoClose(); fireRefresh( refreshedAlready, new RefreshEvent( entityName, object, this ) ); } private void fireRefresh(final RefreshEvent event) { try { if ( !getSessionFactory().getSessionFactoryOptions().isAllowRefreshDetachedEntity() ) { if ( event.getEntityName() != null ) { if ( !contains( event.getEntityName(), event.getObject() ) ) { throw new IllegalArgumentException( "Entity not managed" ); } } else { if ( !contains( event.getObject() ) ) { throw new IllegalArgumentException( "Entity not managed" ); } } } pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_REFRESH .fireEventOnEachListener( event, RefreshEventListener::onRefresh ); } catch (RuntimeException e) { if ( !getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) { if ( e instanceof HibernateException ) { throw e; } } //including HibernateException throw getExceptionConverter().convert( e ); } finally { delayedAfterCompletion(); } } private void fireRefresh(final RefreshContext refreshedAlready, final RefreshEvent event) { try { pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_REFRESH .fireEventOnEachListener( event, refreshedAlready, RefreshEventListener::onRefresh ); } catch (RuntimeException e) { throw getExceptionConverter().convert( e ); } finally { delayedAfterCompletion(); } } // replicate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void replicate(Object obj, ReplicationMode replicationMode) throws HibernateException { fireReplicate( new ReplicateEvent( obj, replicationMode, this ) ); } @Override public void replicate(String entityName, Object obj, ReplicationMode replicationMode) throws HibernateException { fireReplicate( new ReplicateEvent( entityName, obj, replicationMode, this ) ); } private void fireReplicate(final ReplicateEvent event) { checkOpen(); pulseTransactionCoordinator(); fastSessionServices.eventListenerGroup_REPLICATE .fireEventOnEachListener( event, ReplicateEventListener::onReplicate ); delayedAfterCompletion(); } // evict() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * remove any hard references to the entity that are held by the infrastructure * (references held by application or other persistent instances are okay) */ @Override public void evict(Object object) throws HibernateException { checkOpen(); pulseTransactionCoordinator(); final EvictEvent event = new EvictEvent( object, this ); fastSessionServices.eventListenerGroup_EVICT .fireEventOnEachListener( event, EvictEventListener::onEvict ); delayedAfterCompletion(); } @Override public boolean autoFlushIfRequired(Set querySpaces) throws HibernateException { checkOpen(); if ( !isTransactionInProgress() ) { // do not auto-flush while outside a transaction return false; } AutoFlushEvent event = new AutoFlushEvent( querySpaces, this ); fastSessionServices.eventListenerGroup_AUTO_FLUSH .fireEventOnEachListener( event, AutoFlushEventListener::onAutoFlush ); return event.isFlushRequired(); } @Override public boolean isDirty() throws HibernateException { checkOpen(); pulseTransactionCoordinator(); log.debug( "Checking session dirtiness" ); if ( actionQueue.areInsertionsOrDeletionsQueued() ) { log.debug( "Session dirty (scheduled updates and insertions)" ); return true; } DirtyCheckEvent event = new DirtyCheckEvent( this ); fastSessionServices.eventListenerGroup_DIRTY_CHECK .fireEventOnEachListener( event, DirtyCheckEventListener::onDirtyCheck ); delayedAfterCompletion(); return event.isDirty(); } @Override public void flush() throws HibernateException { checkOpen(); doFlush(); } private void doFlush() { pulseTransactionCoordinator(); checkTransactionNeededForUpdateOperation(); try { if ( persistenceContext.getCascadeLevel() > 0 ) { throw new HibernateException( "Flush during cascade is dangerous" ); } FlushEvent event = new FlushEvent( this ); fastSessionServices.eventListenerGroup_FLUSH .fireEventOnEachListener( event, FlushEventListener::onFlush ); delayedAfterCompletion(); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public void setFlushMode(FlushModeType flushModeType) { checkOpen(); setHibernateFlushMode( FlushModeTypeHelper.getFlushMode( flushModeType ) ); } @Override public void forceFlush(EntityEntry entityEntry) throws HibernateException { forceFlush( entityEntry.getEntityKey() ); } @Override public void forceFlush(EntityKey key) throws HibernateException { if ( log.isDebugEnabled() ) { log.debugf( "Flushing to force deletion of re-saved object: %s", MessageHelper.infoString( key.getPersister(), key.getIdentifier(), getFactory() ) ); } if ( persistenceContext.getCascadeLevel() > 0 ) { throw new ObjectDeletedException( "deleted object would be re-saved by cascade (remove deleted object from associations)", key.getIdentifier(), key.getPersister().getEntityName() ); } checkOpenOrWaitingForAutoClose(); doFlush(); } @Override public Object instantiate(String entityName, Object id) throws HibernateException { final EntityPersister persister = getFactory().getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( entityName ); return instantiate( persister, id ); } /** * give the interceptor an opportunity to override the default instantiation */ @Override public Object instantiate(EntityPersister persister, Object id) throws HibernateException { checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); Object result = getInterceptor().instantiate( persister.getEntityName(), persister.getRepresentationStrategy(), id ); if ( result == null ) { result = persister.instantiate( id, this ); } delayedAfterCompletion(); return result; } @Override public EntityPersister getEntityPersister(final String entityName, final Object object) { checkOpenOrWaitingForAutoClose(); if ( entityName == null ) { return getFactory().getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( guessEntityName( object ) ); } else { // try block is a hack around fact that currently tuplizers are not // given the opportunity to resolve a subclass entity name. this // allows the (we assume custom) interceptor the ability to // influence this decision if we were not able to based on the // given entityName try { return getFactory().getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( entityName ) .getSubclassEntityPersister( object, getFactory() ); } catch ( HibernateException e ) { try { return getEntityPersister( null, object ); } catch ( HibernateException e2 ) { throw e; } } } } // not for internal use: @Override public Object getIdentifier(Object object) throws HibernateException { checkOpen(); checkTransactionSynchStatus(); final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { if ( lazyInitializer.getSession() != this ) { throw new TransientObjectException( "The proxy was not associated with this session" ); } return lazyInitializer.getInternalIdentifier(); } else { final EntityEntry entry = persistenceContext.getEntry( object ); if ( entry == null ) { throw new TransientObjectException( "The instance was not associated with this session" ); } return entry.getId(); } } /** * Get the id value for an object that is actually associated with the session. This * is a bit stricter than getEntityIdentifierIfNotUnsaved(). */ @Override public Object getContextEntityIdentifier(Object object) { checkOpenOrWaitingForAutoClose(); final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { return lazyInitializer.getInternalIdentifier(); } else { final EntityEntry entry = persistenceContext.getEntry( object ); return entry != null ? entry.getId() : null; } } @Override public boolean contains(Object object) { checkOpen(); pulseTransactionCoordinator(); if ( object == null ) { return false; } try { final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { //do not use proxiesByKey, since not all //proxies that point to this session's //instances are in that collection! if ( lazyInitializer.isUninitialized() ) { //if it is an uninitialized proxy, pointing //with this session, then when it is accessed, //the underlying instance will be "contained" return lazyInitializer.getSession() == this; } else { //if it is initialized, see if the underlying //instance is contained, since we need to //account for the fact that it might have been //evicted object = lazyInitializer.getImplementation(); } } // 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 // that the entity has not been removed EntityEntry entry = persistenceContext.getEntry( object ); delayedAfterCompletion(); if ( entry == null ) { if ( lazyInitializer == null && persistenceContext.getEntry( object ) == null ) { // check if it is even an entity -> if not throw an exception (per JPA) try { final String entityName = getEntityNameResolver().resolveEntityName( object ); if ( entityName == null ) { throw new IllegalArgumentException( "Could not resolve entity name for class '" + object.getClass() + "'" ); } getFactory().getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( entityName ); } catch ( HibernateException e ) { throw new IllegalArgumentException( "Class '" + object.getClass() + "' is not an entity class", e ); } } return false; } else { return !entry.getStatus().isDeletedOrGone(); } } catch ( MappingException e ) { throw new IllegalArgumentException( e.getMessage(), e ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public boolean contains(String entityName, Object object) { checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); if ( object == null ) { return false; } try { final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer == null && persistenceContext.getEntry( object ) == null ) { // check if it is an entity -> if not throw an exception (per JPA) try { getFactory().getMappingMetamodel() .getEntityDescriptor( entityName ); } catch (HibernateException e) { throw new IllegalArgumentException( "Not an entity [" + entityName + "] : " + object ); } } if ( lazyInitializer != null ) { //do not use proxiesByKey, since not all //proxies that point to this session's //instances are in that collection! if ( lazyInitializer.isUninitialized() ) { //if it is an uninitialized proxy, pointing //with this session, then when it is accessed, //the underlying instance will be "contained" return lazyInitializer.getSession() == this; } else { //if it is initialized, see if the underlying //instance is contained, since we need to //account for the fact that it might have been //evicted object = lazyInitializer.getImplementation(); } } // 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 // that the entity has not been removed final EntityEntry entry = persistenceContext.getEntry( object ); delayedAfterCompletion(); return entry != null && !entry.getStatus().isDeletedOrGone(); } catch ( MappingException e ) { throw new IllegalArgumentException( e.getMessage(), e ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public ProcedureCall createStoredProcedureCall(String procedureName) { checkOpen(); // checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) { checkOpen(); // checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName, resultSetMappings ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) { checkOpen(); // checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName, resultClasses ); } @Override public SessionFactoryImplementor getSessionFactory() { // checkTransactionSynchStatus(); return getFactory(); } @Override public void initializeCollection(PersistentCollection collection, boolean writing) { checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this ); fastSessionServices.eventListenerGroup_INIT_COLLECTION .fireEventOnEachListener( event, InitializeCollectionEventListener::onInitializeCollection ); delayedAfterCompletion(); } @Override public String bestGuessEntityName(Object object) { final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { // it is possible for this method to be called during flush processing, // so make certain that we do not accidentally initialize an uninitialized proxy if ( lazyInitializer.isUninitialized() ) { return lazyInitializer.getEntityName(); } object = lazyInitializer.getImplementation(); } final EntityEntry entry = persistenceContext.getEntry( object ); if ( entry == null ) { return guessEntityName( object ); } else { return entry.getPersister().getEntityName(); } } @Override public String bestGuessEntityName(Object object, EntityEntry entry) { final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { // it is possible for this method to be called during flush processing, // so make certain that we do not accidentally initialize an uninitialized proxy if ( lazyInitializer.isUninitialized() ) { return lazyInitializer.getEntityName(); } object = lazyInitializer.getImplementation(); } if ( entry == null ) { return guessEntityName( object ); } else { return entry.getPersister().getEntityName(); } } @Override public String getEntityName(Object object) { checkOpen(); // checkTransactionSynchStatus(); final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { if ( !persistenceContext.containsProxy( object ) ) { throw new TransientObjectException( "proxy was not associated with the session" ); } object = lazyInitializer.getImplementation(); } EntityEntry entry = persistenceContext.getEntry( object ); if ( entry == null ) { throwTransientObjectException( object ); } return entry.getPersister().getEntityName(); } @Override @SuppressWarnings("unchecked") public T getReference(T object) { checkOpen(); final LazyInitializer lazyInitializer = extractLazyInitializer( object ); if ( lazyInitializer != null ) { return (T) getReference( lazyInitializer.getPersistentClass(), lazyInitializer.getIdentifier() ); } else { EntityPersister persister = getEntityPersister( null, object ); return (T) getReference( persister.getMappedClass(), persister.getIdentifier(object, this) ); } } private void throwTransientObjectException(Object object) throws HibernateException { throw new TransientObjectException( "object references an unsaved transient instance - save the transient instance before flushing: " + guessEntityName( object ) ); } @Override public String guessEntityName(Object object) throws HibernateException { checkOpenOrWaitingForAutoClose(); return getEntityNameResolver().resolveEntityName( object ); } @Override public void cancelQuery() throws HibernateException { checkOpen(); getJdbcCoordinator().cancelLastQuery(); } @Override public String toString() { final StringBuilder string = new StringBuilder( 500 ) .append( "SessionImpl(" ).append( System.identityHashCode( this ) ); if ( !isClosed() ) { if ( log.isTraceEnabled() ) { string.append( persistenceContext ) .append( ";" ) .append( actionQueue ); } else { string.append( "" ); } } else { string.append( "" ); } return string.append( ')' ).toString(); } @Override public ActionQueue getActionQueue() { checkOpenOrWaitingForAutoClose(); // checkTransactionSynchStatus(); return actionQueue; } @Override public PersistenceContext getPersistenceContext() { checkOpenOrWaitingForAutoClose(); // checkTransactionSynchStatus(); return persistenceContext; } @Override public PersistenceContext getPersistenceContextInternal() { return persistenceContext; } @Override public SessionStatistics getStatistics() { pulseTransactionCoordinator(); return new SessionStatisticsImpl( this ); } @Override public boolean isEventSource() { pulseTransactionCoordinator(); return true; } @Override public EventSource asEventSource() { return this; } @Override public boolean isDefaultReadOnly() { return persistenceContext.isDefaultReadOnly(); } @Override public void setDefaultReadOnly(boolean defaultReadOnly) { persistenceContext.setDefaultReadOnly( defaultReadOnly ); } @Override public boolean isReadOnly(Object entityOrProxy) { checkOpen(); // checkTransactionSynchStatus(); return persistenceContext.isReadOnly( entityOrProxy ); } @Override public void setReadOnly(Object entity, boolean readOnly) { checkOpen(); // checkTransactionSynchStatus(); persistenceContext.setReadOnly( entity, readOnly ); } @Override public CacheStoreMode getCacheStoreMode() { return getCacheMode().getJpaStoreMode(); } @Override public CacheRetrieveMode getCacheRetrieveMode() { return getCacheMode().getJpaRetrieveMode(); } @Override public void setCacheStoreMode(CacheStoreMode cacheStoreMode) { setCacheMode( fromJpaModes( getCacheMode().getJpaRetrieveMode(), cacheStoreMode ) ); } @Override public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { setCacheMode( fromJpaModes( cacheRetrieveMode, getCacheMode().getJpaStoreMode() ) ); } @Override public void afterScrollOperation() { // nothing to do in a stateful session } @Override public LoadQueryInfluencers getLoadQueryInfluencers() { return loadQueryInfluencers; } // filter support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public Filter getEnabledFilter(String filterName) { pulseTransactionCoordinator(); return loadQueryInfluencers.getEnabledFilter( filterName ); } @Override public Filter enableFilter(String filterName) { checkOpen(); pulseTransactionCoordinator(); return loadQueryInfluencers.enableFilter( filterName ); } @Override public void disableFilter(String filterName) { checkOpen(); pulseTransactionCoordinator(); loadQueryInfluencers.disableFilter( filterName ); } // fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public boolean isFetchProfileEnabled(String name) throws UnknownProfileException { return loadQueryInfluencers.isFetchProfileEnabled( name ); } @Override public void enableFetchProfile(String name) throws UnknownProfileException { loadQueryInfluencers.enableFetchProfile( name ); } @Override public void disableFetchProfile(String name) throws UnknownProfileException { loadQueryInfluencers.disableFetchProfile( name ); } @Override public void setSubselectFetchingEnabled(boolean enabled) { loadQueryInfluencers.setSubselectFetchEnabled( enabled ); } @Override public boolean isSubselectFetchingEnabled() { return loadQueryInfluencers.getSubselectFetchEnabled(); } @Override public void setFetchBatchSize(int batchSize) { loadQueryInfluencers.setBatchSize( batchSize ); } @Override public int getFetchBatchSize() { return loadQueryInfluencers.getBatchSize(); } @Override public LobHelper getLobHelper() { if ( lobHelper == null ) { lobHelper = new LobHelperImpl(); } return lobHelper; } private transient LobHelperImpl lobHelper; private Transaction getTransactionIfAccessible() { // We do not want an exception to be thrown if the transaction // is not accessible. If the transaction is not accessible, // then return null. return fastSessionServices.isJtaTransactionAccessible ? accessTransaction() : null; } @Override public void beforeTransactionCompletion() { log.trace( "SessionImpl#beforeTransactionCompletion()" ); flushBeforeTransactionCompletion(); actionQueue.beforeTransactionCompletion(); try { getInterceptor().beforeTransactionCompletion( getTransactionIfAccessible() ); } catch (Throwable t) { log.exceptionInBeforeTransactionCompletionInterceptor( t ); } super.beforeTransactionCompletion(); } @Override public void afterTransactionCompletion(boolean successful, boolean delayed) { if ( log.isTraceEnabled() ) { log.tracef( "SessionImpl#afterTransactionCompletion(successful=%s, delayed=%s)", successful, delayed ); } if ( !isClosed() || waitingForAutoClose ) { if ( autoClear ||!successful ) { internalClear(); } } persistenceContext.afterTransactionCompletion(); actionQueue.afterTransactionCompletion( successful ); getEventListenerManager().transactionCompletion( successful ); final StatisticsImplementor statistics = getFactory().getStatistics(); if ( statistics.isStatisticsEnabled() ) { statistics.endTransaction( successful ); } try { getInterceptor().afterTransactionCompletion( getTransactionIfAccessible() ); } catch (Throwable t) { log.exceptionInAfterTransactionCompletionInterceptor( t ); } if ( !delayed ) { if ( shouldAutoClose() && (!isClosed() || waitingForAutoClose) ) { managedClose(); } } super.afterTransactionCompletion( successful, delayed ); } private static class LobHelperImpl implements LobHelper { @Override public Blob createBlob(byte[] bytes) { return lobCreator().createBlob( bytes ); } private LobCreator lobCreator() { // Always use NonContextualLobCreator. If ContextualLobCreator is // used both here and in WrapperOptions, return NonContextualLobCreator.INSTANCE; } @Override public Blob createBlob(InputStream stream, long length) { return lobCreator().createBlob( stream, length ); } @Override public Clob createClob(String string) { return lobCreator().createClob( string ); } @Override public Clob createClob(Reader reader, long length) { return lobCreator().createClob( reader, length ); } @Override public NClob createNClob(String string) { return lobCreator().createNClob( string ); } @Override public NClob createNClob(Reader reader, long length) { return lobCreator().createNClob( reader, length ); } } private static class SharedSessionBuilderImpl extends SessionFactoryImpl.SessionBuilderImpl implements SharedSessionBuilder, SharedSessionCreationOptions { private final SessionImpl session; private boolean shareTransactionContext; private SharedSessionBuilderImpl(SessionImpl session) { super( (SessionFactoryImpl) session.getFactory() ); this.session = session; super.tenantIdentifier( session.getTenantIdentifierValue() ); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionBuilder @Override public SharedSessionBuilderImpl tenantIdentifier(String tenantIdentifier) { // todo : is this always true? Or just in the case of sharing JDBC resources? throw new SessionException( "Cannot redefine tenant identifier on child session" ); } @Override public SharedSessionBuilderImpl tenantIdentifier(Object tenantIdentifier) { // todo : is this always true? Or just in the case of sharing JDBC resources? throw new SessionException( "Cannot redefine tenant identifier on child session" ); } @Override public SharedSessionBuilderImpl interceptor() { super.interceptor( session.getInterceptor() ); return this; } @Override public SharedSessionBuilderImpl interceptor(Interceptor interceptor) { super.interceptor( interceptor ); return this; } @Override public SharedSessionBuilderImpl noInterceptor() { super.noInterceptor(); return this; } @Override public SharedSessionBuilderImpl connection() { this.shareTransactionContext = true; return this; } @Override public SharedSessionBuilderImpl connection(Connection connection) { super.connection( connection ); return this; } @Override @Deprecated(since = "6.0") public SharedSessionBuilderImpl connectionReleaseMode() { final PhysicalConnectionHandlingMode handlingMode = PhysicalConnectionHandlingMode.interpret( ConnectionAcquisitionMode.AS_NEEDED, session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode() ); connectionHandlingMode( handlingMode ); return this; } @Override public SharedSessionBuilderImpl connectionHandlingMode() { connectionHandlingMode( session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode() ); return this; } @Override public SharedSessionBuilderImpl autoJoinTransactions() { super.autoJoinTransactions( session.isAutoCloseSessionEnabled() ); return this; } @Override public SharedSessionBuilderImpl autoJoinTransactions(boolean autoJoinTransactions) { super.autoJoinTransactions( autoJoinTransactions ); return this; } @Override public SharedSessionBuilderImpl autoClose(boolean autoClose) { super.autoClose( autoClose ); return this; } @Override public SharedSessionBuilderImpl flushMode() { flushMode( session.getHibernateFlushMode() ); return this; } @Override public SharedSessionBuilderImpl autoClose() { autoClose( session.autoClose ); return this; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionCreationOptions @Override public boolean isTransactionCoordinatorShared() { return shareTransactionContext; } @Override public TransactionCoordinator getTransactionCoordinator() { return shareTransactionContext ? session.getTransactionCoordinator() : null; } @Override public JdbcCoordinator getJdbcCoordinator() { return shareTransactionContext ? session.getJdbcCoordinator() : null; } @Override public TransactionImplementor getTransaction() { return shareTransactionContext ? session.getCurrentTransaction() : null; } @Override public ActionQueue.TransactionCompletionProcesses getTransactionCompletionProcesses() { return shareTransactionContext ? session.getActionQueue().getTransactionCompletionProcesses() : null; } } @Deprecated private class LockRequestImpl implements LockRequest { private final LockOptions lockOptions; private LockRequestImpl(LockOptions lockOptions) { this.lockOptions = new LockOptions(); LockOptions.copy( lockOptions, this.lockOptions ); } @Override public LockMode getLockMode() { return lockOptions.getLockMode(); } @Override public LockRequest setLockMode(LockMode lockMode) { lockOptions.setLockMode( lockMode ); return this; } @Override public int getTimeOut() { return lockOptions.getTimeOut(); } @Override public LockRequest setTimeOut(int timeout) { lockOptions.setTimeOut( timeout ); return this; } @Override @Deprecated @SuppressWarnings("deprecation") public boolean getScope() { return lockOptions.getScope(); } @Override @Deprecated @SuppressWarnings("deprecation") public LockRequest setScope(boolean scope) { lockOptions.setScope( scope ); return this; } @Override @Deprecated @SuppressWarnings("deprecation") public void lock(String entityName, Object object) throws HibernateException { fireLock( entityName, object, lockOptions ); } @Override public void lock(Object object) throws HibernateException { fireLock( object, lockOptions ); } } @Override protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) { transactionObserver = new TransactionObserver() { @Override public void afterBegin() { } @Override public void beforeCompletion() { if ( isOpen() && getHibernateFlushMode() != FlushMode.MANUAL ) { managedFlush(); } actionQueue.beforeTransactionCompletion(); try { getInterceptor().beforeTransactionCompletion( getTransactionIfAccessible() ); } catch ( Throwable t ) { log.exceptionInBeforeTransactionCompletionInterceptor( t ); } } @Override public void afterCompletion(boolean successful, boolean delayed) { afterTransactionCompletion( successful, delayed ); if ( !isClosed() && autoClose ) { managedClose(); } } }; transactionCoordinator.addObserver( transactionObserver ); } @Override protected void removeSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) { super.removeSharedSessionTransactionObserver( transactionCoordinator ); transactionCoordinator.removeObserver( transactionObserver ); } private EntityPersister requireEntityPersister(Class entityClass) { return getFactory().getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( entityClass ); } private EntityPersister requireEntityPersister(String entityName) { return getFactory().getRuntimeMetamodels() .getMappingMetamodel() .getEntityDescriptor( entityName ); } @Override public void startTransactionBoundary() { checkOpenOrWaitingForAutoClose(); super.startTransactionBoundary(); } @Override public void afterTransactionBegin() { checkOpenOrWaitingForAutoClose(); getInterceptor().afterTransactionBegin( getTransactionIfAccessible() ); } @Override public void flushBeforeTransactionCompletion() { if ( mustFlushBeforeCompletion() ) { try { managedFlush(); } catch ( RuntimeException re ) { throw ExceptionMapperStandardImpl.INSTANCE .mapManagedFlushFailure( "error during managed flush", re, this ); } } } private boolean mustFlushBeforeCompletion() { return isTransactionFlushable() && getHibernateFlushMode() != FlushMode.MANUAL; } private boolean isTransactionFlushable() { if ( getCurrentTransaction() == null ) { // assume it is flushable - CMT, auto-commit, etc return true; } else { final TransactionStatus status = getCurrentTransaction().getStatus(); return status == TransactionStatus.ACTIVE || status == TransactionStatus.COMMITTING; } } @Override public SessionImplementor getSession() { return this; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HibernateEntityManagerImplementor impl // @Override // public LockOptions getLockRequest(LockModeType lockModeType, Map 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 @Override public void remove(Object entity) { checkOpen(); try { delete( entity ); } catch (MappingException e) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw getExceptionConverter().convert( e ); } } @Override public T find(Class entityClass, Object primaryKey) { return find( entityClass, primaryKey, null, null ); } @Override public T find(Class entityClass, Object primaryKey, Map properties) { return find( entityClass, primaryKey, null, properties ); } @Override public T find(Class entityClass, Object primaryKey, LockModeType lockModeType) { return find( entityClass, primaryKey, lockModeType, null ); } @Override public T find(Class entityClass, Object primaryKey, LockModeType lockModeType, Map properties) { checkOpen(); LockOptions lockOptions = null; try { if ( lockModeType != null ) { checkTransactionNeededForLock( lockModeType ); lockOptions = buildLockOptions( lockModeType, properties ); } final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph(); effectiveEntityGraph.applyConfiguredGraph( properties ); loadQueryInfluencers.setReadOnly( getReadOnlyHint( properties ) ); if ( effectiveEntityGraph.getSemantic() == GraphSemantic.FETCH ) { setEnforcingFetchGraph( true ); } return byId( entityClass ) .with( determineAppropriateLocalCacheMode( properties ) ) .with( lockOptions ) .load( primaryKey ); } catch ( EntityNotFoundException enfe ) { /* This may happen if the entity has an associations mapped with @NotFound(action = NotFoundAction.EXCEPTION) and this associated entity is not found. */ if ( enfe instanceof FetchNotFoundException ) { throw enfe; } // DefaultLoadEventListener#returnNarrowedProxy() may throw ENFE (see HHH-7861 for details), // which find() should not throw. Find() should return null if the entity was not found. if ( log.isDebugEnabled() ) { String entityName = entityClass != null ? entityClass.getName(): null; String identifierValue = primaryKey != null ? primaryKey.toString() : null ; log.ignoringEntityNotFound( entityName, identifierValue ); } return null; } catch ( ObjectDeletedException e ) { //the spec is silent about people doing remove() find() on the same PC return null; } catch ( ObjectNotFoundException e ) { //should not happen on the entity itself with get throw new IllegalArgumentException( e.getMessage(), e ); } catch ( MappingException | TypeMismatchException | ClassCastException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( JDBCException e ) { if ( accessTransaction().isActive() && accessTransaction().getRollbackOnly() ) { // Assume this is similar to the WildFly / IronJacamar "feature" described under HHH-12472. // Just log the exception and return null. if ( log.isDebugEnabled() ) { log.debug( "JDBCException was thrown for a transaction marked for rollback; " + "this is probably due to an operation failing fast due to the " + "transaction marked for rollback.", e ); } return null; } else { throw getExceptionConverter().convert( e, lockOptions ); } } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e, lockOptions ); } finally { loadQueryInfluencers.getEffectiveEntityGraph().clear(); loadQueryInfluencers.setReadOnly( null ); setEnforcingFetchGraph( false ); } } private void checkTransactionNeededForLock(LockModeType lockModeType) { if ( lockModeType != LockModeType.NONE ) { checkTransactionNeededForUpdateOperation(); } } private static Boolean getReadOnlyHint(Map properties) { return properties == null ? null : (Boolean) properties.get( HINT_READ_ONLY ); } protected CacheMode determineAppropriateLocalCacheMode(Map localProperties) { CacheRetrieveMode retrieveMode = null; CacheStoreMode storeMode = null; if ( localProperties != null ) { retrieveMode = determineCacheRetrieveMode( localProperties ); storeMode = determineCacheStoreMode( localProperties ); } if ( retrieveMode == null ) { // use the EM setting retrieveMode = fastSessionServices.getCacheRetrieveMode( this.properties ); } if ( storeMode == null ) { // use the EM setting storeMode = fastSessionServices.getCacheStoreMode( this.properties ); } return interpretCacheMode( storeMode, retrieveMode ); } private static CacheRetrieveMode determineCacheRetrieveMode(Map settings) { final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); return cacheRetrieveMode == null ? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE ) : cacheRetrieveMode; } private static CacheStoreMode determineCacheStoreMode(Map settings) { final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE ); return cacheStoreMode == null ? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE ) : cacheStoreMode; } private void checkTransactionNeededForUpdateOperation() { checkTransactionNeededForUpdateOperation( "no transaction is in progress" ); } @Override public T getReference(Class entityClass, Object id) { checkOpen(); try { return byId( entityClass ).getReference( id ); } catch ( MappingException | TypeMismatchException | ClassCastException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public Object getReference(String entityName, Object id) { checkOpen(); try { return byId( entityName ).getReference( id ); } catch ( MappingException | TypeMismatchException | ClassCastException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public void lock(Object entity, LockModeType lockModeType) { lock( entity, lockModeType, null ); } @Override public void lock(Object entity, LockModeType lockModeType, Map properties) { checkOpen(); checkTransactionNeededForUpdateOperation(); if ( !contains( entity ) ) { throw new IllegalArgumentException( "entity not in the persistence context" ); } final LockOptions lockOptions = buildLockOptions( lockModeType, properties ); try { buildLockRequest( lockOptions ).lock( entity ); } catch (RuntimeException e) { throw getExceptionConverter().convert( e, lockOptions ); } } @Override public void refresh(Object entity, Map properties) { refresh( entity, null, properties ); } @Override public void refresh(Object entity, LockModeType lockModeType) { refresh( entity, lockModeType, null ); } @Override public void refresh(Object entity, LockModeType lockModeType, Map properties) { checkOpen(); final CacheMode previousCacheMode = getCacheMode(); final CacheMode refreshCacheMode = determineAppropriateLocalCacheMode( properties ); LockOptions lockOptions = null; try { setCacheMode( refreshCacheMode ); 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 ); } } catch ( MappingException e ) { throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e, lockOptions ); } finally { setCacheMode( previousCacheMode ); } } private LockOptions buildLockOptions(LockModeType lockModeType, Map 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 ) { applyPropertiesToLockOptions( properties, () -> lockOptions ); } return lockOptions; } @Override public void detach(Object entity) { checkOpen(); try { evict( entity ); } catch (RuntimeException e) { throw getExceptionConverter().convert( e ); } } @Override public LockModeType getLockMode(Object entity) { checkOpen(); if ( !isTransactionInProgress() ) { throw new TransactionRequiredException( "Call to EntityManager#getLockMode should occur within transaction according to spec" ); } if ( !contains( entity ) ) { throw getExceptionConverter().convert( new IllegalArgumentException( "entity not in the persistence context" ) ); } return LockModeTypeHelper.getLockModeType( getCurrentLockMode( entity ) ); } @Override public void setProperty(String propertyName, Object value) { checkOpen(); if ( !( value instanceof Serializable ) ) { log.warnf( "Property '%s' is not serializable, value won't be set", propertyName ); return; } if ( propertyName == null ) { log.warn( "Property having key null is illegal, value won't be set" ); return; } // store property for future reference: if ( properties == null ) { properties = computeCurrentSessionProperties(); } properties.put( propertyName, value ); // now actually update the setting, if it's one which affects this Session interpretProperty( propertyName, value ); } private void interpretProperty(String propertyName, Object value) { switch ( propertyName ) { case HINT_FLUSH_MODE: setHibernateFlushMode( ConfigurationHelper.getFlushMode( value, FlushMode.AUTO ) ); break; case JPA_LOCK_SCOPE: case JAKARTA_LOCK_SCOPE: properties.put( JPA_LOCK_SCOPE, value); properties.put( JAKARTA_LOCK_SCOPE, value); applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); break; case JPA_LOCK_TIMEOUT: case JAKARTA_LOCK_TIMEOUT: properties.put( JPA_LOCK_TIMEOUT, value ); properties.put( JAKARTA_LOCK_TIMEOUT, value ); applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); break; case JPA_SHARED_CACHE_RETRIEVE_MODE: case JAKARTA_SHARED_CACHE_RETRIEVE_MODE: properties.put( JPA_SHARED_CACHE_RETRIEVE_MODE, value ); properties.put( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, value ); setCacheMode( interpretCacheMode( determineCacheStoreMode( properties ), (CacheRetrieveMode) value ) ); break; case JPA_SHARED_CACHE_STORE_MODE: case JAKARTA_SHARED_CACHE_STORE_MODE: properties.put( JPA_SHARED_CACHE_STORE_MODE, value ); properties.put( JAKARTA_SHARED_CACHE_STORE_MODE, value ); setCacheMode( interpretCacheMode( (CacheStoreMode) value, determineCacheRetrieveMode( properties ) ) ); break; case CRITERIA_COPY_TREE: setCriteriaCopyTreeEnabled( parseBoolean( value.toString() ) ); break; case HINT_FETCH_PROFILE: enableFetchProfile( (String) value ); break; case USE_SUBSELECT_FETCH: case HINT_ENABLE_SUBSELECT_FETCH: setSubselectFetchingEnabled( Boolean.parseBoolean( value.toString() ) ); break; case DEFAULT_BATCH_FETCH_SIZE: case HINT_BATCH_FETCH_SIZE: setFetchBatchSize( Integer.parseInt( value.toString() ) ); break; case STATEMENT_BATCH_SIZE: case HINT_JDBC_BATCH_SIZE: setJdbcBatchSize( Integer.parseInt( value.toString() ) ); break; } } private Map computeCurrentSessionProperties() { final Map 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: map.put( HINT_FLUSH_MODE, getHibernateFlushMode().name() ); return map; } @Override public Map getProperties() { if ( properties == null ) { properties = computeCurrentSessionProperties(); } return unmodifiableMap( properties ); } @Override public ProcedureCall createNamedStoredProcedureQuery(String name) { checkOpen(); try { final NamedCallableQueryMemento memento = getFactory().getQueryEngine() .getNamedObjectRepository() .getCallableQueryMemento( name ); if ( memento == null ) { throw new IllegalArgumentException( "No @NamedStoredProcedureQuery was found with that name : " + name ); } return memento.makeProcedureCall( this ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public ProcedureCall createStoredProcedureQuery(String procedureName) { try { return createStoredProcedureCall( procedureName ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public ProcedureCall createStoredProcedureQuery(String procedureName, Class... resultClasses) { try { return createStoredProcedureCall( procedureName, resultClasses ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override public ProcedureCall createStoredProcedureQuery(String procedureName, String... resultSetMappings) { checkOpen(); try { try { return createStoredProcedureCall( procedureName, resultSetMappings ); } catch ( UnknownSqlResultSetMappingException e ) { throw new IllegalArgumentException( e.getMessage(), e ); } } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); } } @Override @SuppressWarnings("unchecked") public T unwrap(Class clazz) { checkOpen(); if ( Session.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( SessionImplementor.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( SharedSessionContractImplementor.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( EntityManager.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( PersistenceContext.class.isAssignableFrom( clazz ) ) { return (T) this; } throw new PersistenceException( "Hibernate cannot unwrap " + clazz ); } @Override public Object getDelegate() { checkOpen(); return this; } @Override public SessionFactoryImplementor getEntityManagerFactory() { checkOpen(); return getFactory(); } @Override public Metamodel getMetamodel() { checkOpen(); return getFactory().getJpaMetamodel(); } /** * Used by JDK serialization... * * @param oos The output stream to which we are being written... * * @throws IOException Indicates a general IO stream exception */ private void writeObject(ObjectOutputStream oos) throws IOException { if ( log.isTraceEnabled() ) { log.tracef( "Serializing Session [%s]", getSessionIdentifier() ); } oos.defaultWriteObject(); persistenceContext.serialize( oos ); actionQueue.serialize( oos ); oos.writeObject( loadQueryInfluencers ); } /** * Used by JDK serialization... * * @param ois The input stream from which we are being read... * * @throws IOException Indicates a general IO stream exception * @throws ClassNotFoundException Indicates a class resolution issue */ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException, SQLException { if ( log.isTraceEnabled() ) { log.tracef( "Deserializing Session [%s]", getSessionIdentifier() ); } ois.defaultReadObject(); persistenceContext = StatefulPersistenceContext.deserialize( ois, this ); actionQueue = ActionQueue.deserialize( ois, this ); loadQueryInfluencers = (LoadQueryInfluencers) ois.readObject(); // LoadQueryInfluencers#getEnabledFilters() tries to validate each enabled // filter, which will fail when called before FilterImpl#afterDeserialize( factory ); // Instead lookup the filter by name and then call FilterImpl#afterDeserialize( factory ). for ( String filterName : loadQueryInfluencers.getEnabledFilterNames() ) { ( (FilterImpl) loadQueryInfluencers.getEnabledFilter( filterName ) ).afterDeserialize( getFactory() ); } } private Boolean getReadOnlyFromLoadQueryInfluencers() { return loadQueryInfluencers != null ? loadQueryInfluencers.getReadOnly() : null; } @Override @Deprecated(forRemoval = true) public boolean isEnforcingFetchGraph() { return isEnforcingFetchGraph; } @Override @Deprecated(forRemoval = true) public void setEnforcingFetchGraph(boolean isEnforcingFetchGraph) { this.isEnforcingFetchGraph = isEnforcingFetchGraph; } }