Upgrade to JPA 2.1+ and Bean Validation 1.1+; remove native support for Hibernate 3.6 and 4.x

Issue: SPR-13481
Issue: SPR-13827
This commit is contained in:
Juergen Hoeller
2016-07-04 23:37:23 +02:00
parent 69ec437fbc
commit 54004e0d78
128 changed files with 299 additions and 26731 deletions

View File

@@ -1,285 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
* a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
* context, providing general infrastructure not related to Hibernate's
* specific configuration API.
*
* <p>This class implements the
* {@link org.springframework.dao.support.PersistenceExceptionTranslator}
* interface, as autodetected by Spring's
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
* for AOP-based translation of native exceptions to Spring DataAccessExceptions.
* Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
* a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
*
* <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
* For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
*
* @author Juergen Hoeller
* @since 2.0
* @see #setExposeTransactionAwareSessionFactory
* @see org.hibernate.SessionFactory#getCurrentSession()
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public abstract class AbstractSessionFactoryBean extends HibernateExceptionTranslator
implements FactoryBean<SessionFactory>, InitializingBean, DisposableBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private DataSource dataSource;
private boolean useTransactionAwareDataSource = false;
private boolean exposeTransactionAwareSessionFactory = true;
private SessionFactory sessionFactory;
/**
* Set the DataSource to be used by the SessionFactory.
* If set, this will override corresponding settings in Hibernate properties.
* <p>If this is set, the Hibernate settings should not define
* a connection provider to avoid meaningless double configuration.
* <p>If using HibernateTransactionManager as transaction strategy, consider
* proxying your target DataSource with a LazyConnectionDataSourceProxy.
* This defers fetching of an actual JDBC Connection until the first JDBC
* Statement gets executed, even within JDBC transactions (as performed by
* HibernateTransactionManager). Such lazy fetching is particularly beneficial
* for read-only operations, in particular if the chances of resolving the
* result in the second-level cache are high.
* <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
* of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
* JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
* @see #setUseTransactionAwareDataSource
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Return the DataSource to be used by the SessionFactory.
*/
public DataSource getDataSource() {
return this.dataSource;
}
/**
* Set whether to use a transaction-aware DataSource for the SessionFactory,
* i.e. whether to automatically wrap the passed-in DataSource with Spring's
* TransactionAwareDataSourceProxy.
* <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
* HibernateTransactionManager or JtaTransactionManager, both of which work nicely
* on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
* fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
* <p>If you switch this flag to "true", Spring's Hibernate access will be able to
* <i>participate in JDBC-based transactions managed outside of Hibernate</i>
* (for example, by Spring's DataSourceTransactionManager). This can be convenient
* if you need a different local transaction strategy for another O/R mapping tool,
* for example, but still want Hibernate access to join into those transactions.
* <p>A further benefit of this option is that <i>plain Sessions opened directly
* via the SessionFactory</i>, outside of Spring's Hibernate support, will still
* participate in active Spring-managed transactions. However, consider using
* Hibernate's {@code getCurrentSession()} method instead (see javadoc of
* "exposeTransactionAwareSessionFactory" property).
* <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination
* with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
* external JDBC-based transactions, it is strongly recommended to set Hibernate's
* Connection release mode to "after_transaction" or "after_statement", which
* guarantees proper Connection handling in such a scenario. In contrast to that,
* HibernateTransactionManager generally requires release mode "on_close".
* <p>Note: If you want to use Hibernate's Connection release mode "after_statement"
* with a DataSource specified on this LocalSessionFactoryBean (for example, a
* JTA-aware DataSource fetched from JNDI), switch this setting to "true".
* Otherwise, the ConnectionProvider used underneath will vote against aggressive
* release and thus silently switch to release mode "after_transaction".
* @see #setDataSource
* @see #setExposeTransactionAwareSessionFactory
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
this.useTransactionAwareDataSource = useTransactionAwareDataSource;
}
/**
* Return whether to use a transaction-aware DataSource for the SessionFactory.
*/
protected boolean isUseTransactionAwareDataSource() {
return this.useTransactionAwareDataSource;
}
/**
* Set whether to expose a transaction-aware current Session from the
* SessionFactory's {@code getCurrentSession()} method, returning the
* Session that's associated with the current Spring-managed transaction, if any.
* <p>Default is "true", letting data access code work with the plain
* Hibernate SessionFactory and its {@code getCurrentSession()} method,
* while still being able to participate in current Spring-managed transactions:
* with any transaction management strategy, either local or JTA / EJB CMT,
* and any transaction synchronization mechanism, either Spring or JTA.
* Furthermore, {@code getCurrentSession()} will also seamlessly work with
* a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
* <p>Turn this flag off to expose the plain Hibernate SessionFactory with
* Hibernate's default {@code getCurrentSession()} behavior, supporting
* plain JTA synchronization only. Alternatively, simply override the
* corresponding Hibernate property "hibernate.current_session_context_class".
* @see SpringSessionContext
* @see org.hibernate.SessionFactory#getCurrentSession()
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see HibernateTransactionManager
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
*/
public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
}
/**
* Return whether to expose a transaction-aware proxy for the SessionFactory.
*/
protected boolean isExposeTransactionAwareSessionFactory() {
return this.exposeTransactionAwareSessionFactory;
}
/**
* Build and expose the SessionFactory.
* @see #buildSessionFactory()
* @see #wrapSessionFactoryIfNecessary
*/
@Override
public void afterPropertiesSet() throws Exception {
SessionFactory rawSf = buildSessionFactory();
this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
afterSessionFactoryCreation();
}
/**
* Wrap the given SessionFactory with a proxy, if demanded.
* <p>The default implementation simply returns the given SessionFactory as-is.
* Subclasses may override this to implement transaction awareness through
* a SessionFactory proxy, for example.
* @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()}
* @return the SessionFactory reference to expose
* @see #buildSessionFactory()
*/
protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
return rawSf;
}
/**
* Return the exposed SessionFactory.
* Will throw an exception if not initialized yet.
* @return the SessionFactory (never {@code null})
* @throws IllegalStateException if the SessionFactory has not been initialized yet
*/
protected final SessionFactory getSessionFactory() {
if (this.sessionFactory == null) {
throw new IllegalStateException("SessionFactory not initialized yet");
}
return this.sessionFactory;
}
/**
* Close the SessionFactory on bean factory shutdown.
*/
@Override
public void destroy() throws HibernateException {
logger.info("Closing Hibernate SessionFactory");
try {
beforeSessionFactoryDestruction();
}
finally {
this.sessionFactory.close();
}
}
/**
* Return the singleton SessionFactory.
*/
@Override
public SessionFactory getObject() {
return this.sessionFactory;
}
@Override
public Class<? extends SessionFactory> getObjectType() {
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
}
@Override
public boolean isSingleton() {
return true;
}
/**
* Build the underlying Hibernate SessionFactory.
* @return the raw SessionFactory (potentially to be wrapped with a
* transaction-aware proxy before it is exposed to the application)
* @throws Exception in case of initialization failure
*/
protected abstract SessionFactory buildSessionFactory() throws Exception;
/**
* Hook that allows post-processing after the SessionFactory has been
* successfully created. The SessionFactory is already available through
* {@code getSessionFactory()} at this point.
* <p>This implementation is empty.
* @throws Exception in case of initialization failure
* @see #getSessionFactory()
*/
protected void afterSessionFactoryCreation() throws Exception {
}
/**
* Hook that allows shutdown processing before the SessionFactory
* will be closed. The SessionFactory is still available through
* {@code getSessionFactory()} at this point.
* <p>This implementation is empty.
* @see #getSessionFactory()
*/
protected void beforeSessionFactoryDestruction() {
}
}

View File

@@ -1,145 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.engine.FilterDefinition;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* Convenient FactoryBean for defining Hibernate FilterDefinitions.
* Exposes a corresponding Hibernate FilterDefinition object.
*
* <p>Typically defined as an inner bean within a LocalSessionFactoryBean
* definition, as the list element for the "filterDefinitions" bean property.
* For example:
*
* <pre class="code">
* &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;
* ...
* &lt;property name="filterDefinitions"&gt;
* &lt;list&gt;
* &lt;bean class="org.springframework.orm.hibernate3.FilterDefinitionFactoryBean"&gt;
* &lt;property name="filterName" value="myFilter"/&gt;
* &lt;property name="parameterTypes"&gt;
* &lt;map&gt;
* &lt;entry key="myParam" value="string"/&gt;
* &lt;entry key="myOtherParam" value="long"/&gt;
* &lt;/map&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
* &lt;/list&gt;
* &lt;/property&gt;
* ...
* &lt;/bean&gt;</pre>
*
* Alternatively, specify a bean id (or name) attribute for the inner bean,
* instead of the "filterName" property.
*
* @author Juergen Hoeller
* @since 1.2
* @see org.hibernate.engine.FilterDefinition
* @see LocalSessionFactoryBean#setFilterDefinitions
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class FilterDefinitionFactoryBean implements FactoryBean<FilterDefinition>, BeanNameAware, InitializingBean {
private final TypeResolver typeResolver = new TypeResolver();
private String filterName;
private Map<String, Type> parameterTypeMap = new HashMap<String, Type>();
private String defaultFilterCondition;
private FilterDefinition filterDefinition;
/**
* Set the name of the filter.
*/
public void setFilterName(String filterName) {
this.filterName = filterName;
}
/**
* Set the parameter types for the filter,
* with parameter names as keys and type names as values.
* See {@code org.hibernate.type.TypeResolver#heuristicType(String)}.
*/
public void setParameterTypes(Map<String, String> parameterTypes) {
if (parameterTypes != null) {
this.parameterTypeMap = new HashMap<String, Type>(parameterTypes.size());
for (Map.Entry<String, String> entry : parameterTypes.entrySet()) {
this.parameterTypeMap.put(entry.getKey(), this.typeResolver.heuristicType(entry.getValue()));
}
}
else {
this.parameterTypeMap = new HashMap<String, Type>();
}
}
/**
* Specify a default filter condition for the filter, if any.
*/
public void setDefaultFilterCondition(String defaultFilterCondition) {
this.defaultFilterCondition = defaultFilterCondition;
}
/**
* If no explicit filter name has been specified, the bean name of
* the FilterDefinitionFactoryBean will be used.
* @see #setFilterName
*/
@Override
public void setBeanName(String name) {
if (this.filterName == null) {
this.filterName = name;
}
}
@Override
public void afterPropertiesSet() {
this.filterDefinition =
new FilterDefinition(this.filterName, this.defaultFilterCondition, this.parameterTypeMap);
}
@Override
public FilterDefinition getObject() {
return this.filterDefinition;
}
@Override
public Class<FilterDefinition> getObjectType() {
return FilterDefinition.class;
}
@Override
public boolean isSingleton() {
return true;
}
}

View File

@@ -1,492 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.sql.SQLException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.exception.GenericJDBCException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.SQLExceptionTranslator;
/**
* Base class for {@link HibernateTemplate} and {@link HibernateInterceptor},
* defining common properties such as SessionFactory and flushing behavior.
*
* <p>Not intended to be used directly.
* See {@link HibernateTemplate} and {@link HibernateInterceptor}.
*
* @author Juergen Hoeller
* @since 1.2
* @see HibernateTemplate
* @see HibernateInterceptor
* @see #setFlushMode
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {
/**
* Never flush is a good strategy for read-only units of work.
* Hibernate will not track and look for changes in this case,
* avoiding any overhead of modification detection.
* <p>In case of an existing Session, FLUSH_NEVER will turn the flush mode
* to NEVER for the scope of the current operation, resetting the previous
* flush mode afterwards.
* @see #setFlushMode
*/
public static final int FLUSH_NEVER = 0;
/**
* Automatic flushing is the default mode for a Hibernate Session.
* A session will get flushed on transaction commit, and on certain find
* operations that might involve already modified instances, but not
* after each unit of work like with eager flushing.
* <p>In case of an existing Session, FLUSH_AUTO will participate in the
* existing flush mode, not modifying it for the current operation.
* This in particular means that this setting will not modify an existing
* flush mode NEVER, in contrast to FLUSH_EAGER.
* @see #setFlushMode
*/
public static final int FLUSH_AUTO = 1;
/**
* Eager flushing leads to immediate synchronization with the database,
* even if in a transaction. This causes inconsistencies to show up and throw
* a respective exception immediately, and JDBC access code that participates
* in the same transaction will see the changes as the database is already
* aware of them then. But the drawbacks are:
* <ul>
* <li>additional communication roundtrips with the database, instead of a
* single batch at transaction commit;
* <li>the fact that an actual database rollback is needed if the Hibernate
* transaction rolls back (due to already submitted SQL statements).
* </ul>
* <p>In case of an existing Session, FLUSH_EAGER will turn the flush mode
* to AUTO for the scope of the current operation and issue a flush at the
* end, resetting the previous flush mode afterwards.
* @see #setFlushMode
*/
public static final int FLUSH_EAGER = 2;
/**
* Flushing at commit only is intended for units of work where no
* intermediate flushing is desired, not even for find operations
* that might involve already modified instances.
* <p>In case of an existing Session, FLUSH_COMMIT will turn the flush mode
* to COMMIT for the scope of the current operation, resetting the previous
* flush mode afterwards. The only exception is an existing flush mode
* NEVER, which will not be modified through this setting.
* @see #setFlushMode
*/
public static final int FLUSH_COMMIT = 3;
/**
* Flushing before every query statement is rarely necessary.
* It is only available for special needs.
* <p>In case of an existing Session, FLUSH_ALWAYS will turn the flush mode
* to ALWAYS for the scope of the current operation, resetting the previous
* flush mode afterwards.
* @see #setFlushMode
*/
public static final int FLUSH_ALWAYS = 4;
/** Constants instance for HibernateAccessor */
private static final Constants constants = new Constants(HibernateAccessor.class);
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private SessionFactory sessionFactory;
private Object entityInterceptor;
private SQLExceptionTranslator jdbcExceptionTranslator;
private SQLExceptionTranslator defaultJdbcExceptionTranslator;
private int flushMode = FLUSH_AUTO;
private String[] filterNames;
/**
* Just needed for entityInterceptorBeanName.
* @see #setEntityInterceptorBeanName
*/
private BeanFactory beanFactory;
/**
* Set the Hibernate SessionFactory that should be used to create
* Hibernate Sessions.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Return the Hibernate SessionFactory that should be used to create
* Hibernate Sessions.
*/
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
/**
* Set the bean name of a Hibernate entity interceptor that allows to inspect
* and change property values before writing to and reading from the database.
* Will get applied to any new Session created by this transaction manager.
* <p>Requires the bean factory to be known, to be able to resolve the bean
* name to an interceptor instance on session creation. Typically used for
* prototype interceptors, i.e. a new interceptor instance per session.
* <p>Can also be used for shared interceptor instances, but it is recommended
* to set the interceptor reference directly in such a scenario.
* @param entityInterceptorBeanName the name of the entity interceptor in
* the bean factory
* @see #setBeanFactory
* @see #setEntityInterceptor
*/
public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
this.entityInterceptor = entityInterceptorBeanName;
}
/**
* Set a Hibernate entity interceptor that allows to inspect and change
* property values before writing to and reading from the database.
* Will get applied to any <b>new</b> Session created by this object.
* <p>Such an interceptor can either be set at the SessionFactory level,
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
* HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
* It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
* to avoid repeated configuration and guarantee consistent behavior in transactions.
* @see #setEntityInterceptorBeanName
* @see LocalSessionFactoryBean#setEntityInterceptor
* @see HibernateTransactionManager#setEntityInterceptor
*/
public void setEntityInterceptor(Interceptor entityInterceptor) {
this.entityInterceptor = entityInterceptor;
}
/**
* Return the current Hibernate entity interceptor, or {@code null} if none.
* Resolves an entity interceptor bean name via the bean factory,
* if necessary.
* @throws IllegalStateException if bean name specified but no bean factory set
* @throws org.springframework.beans.BeansException if bean name resolution via the bean factory failed
* @see #setEntityInterceptor
* @see #setEntityInterceptorBeanName
* @see #setBeanFactory
*/
public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
if (this.entityInterceptor instanceof String) {
if (this.beanFactory == null) {
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
}
return this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
}
return (Interceptor) this.entityInterceptor;
}
/**
* Set the JDBC exception translator for this instance.
* <p>Applied to any SQLException root cause of a Hibernate JDBCException,
* overriding Hibernate's default SQLException translation (which is
* based on Hibernate's Dialect for a specific target database).
* @param jdbcExceptionTranslator the exception translator
* @see java.sql.SQLException
* @see org.hibernate.JDBCException
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
*/
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
}
/**
* Return the JDBC exception translator for this instance, if any.
*/
public SQLExceptionTranslator getJdbcExceptionTranslator() {
return this.jdbcExceptionTranslator;
}
/**
* Set the flush behavior by the name of the respective constant
* in this class, e.g. "FLUSH_AUTO". Default is "FLUSH_AUTO".
* @param constantName name of the constant
* @see #setFlushMode
* @see #FLUSH_AUTO
*/
public void setFlushModeName(String constantName) {
setFlushMode(constants.asNumber(constantName).intValue());
}
/**
* Set the flush behavior to one of the constants in this class.
* Default is FLUSH_AUTO.
* @see #setFlushModeName
* @see #FLUSH_AUTO
*/
public void setFlushMode(int flushMode) {
this.flushMode = flushMode;
}
/**
* Return if a flush should be forced after executing the callback code.
*/
public int getFlushMode() {
return this.flushMode;
}
/**
* Set the name of a Hibernate filter to be activated for all
* Sessions that this accessor works with.
* <p>This filter will be enabled at the beginning of each operation
* and correspondingly disabled at the end of the operation.
* This will work for newly opened Sessions as well as for existing
* Sessions (for example, within a transaction).
* @see #enableFilters(org.hibernate.Session)
* @see org.hibernate.Session#enableFilter(String)
* @see LocalSessionFactoryBean#setFilterDefinitions
*/
public void setFilterName(String filter) {
this.filterNames = new String[] {filter};
}
/**
* Set one or more names of Hibernate filters to be activated for all
* Sessions that this accessor works with.
* <p>Each of those filters will be enabled at the beginning of each
* operation and correspondingly disabled at the end of the operation.
* This will work for newly opened Sessions as well as for existing
* Sessions (for example, within a transaction).
* @see #enableFilters(org.hibernate.Session)
* @see org.hibernate.Session#enableFilter(String)
* @see LocalSessionFactoryBean#setFilterDefinitions
*/
public void setFilterNames(String... filterNames) {
this.filterNames = filterNames;
}
/**
* Return the names of Hibernate filters to be activated, if any.
*/
public String[] getFilterNames() {
return this.filterNames;
}
/**
* The bean factory just needs to be known for resolving entity interceptor
* bean names. It does not need to be set for any other mode of operation.
* @see #setEntityInterceptorBeanName
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() {
if (getSessionFactory() == null) {
throw new IllegalArgumentException("Property 'sessionFactory' is required");
}
}
/**
* Apply the flush mode that's been specified for this accessor
* to the given Session.
* @param session the current Hibernate Session
* @param existingTransaction if executing within an existing transaction
* @return the previous flush mode to restore after the operation,
* or {@code null} if none
* @see #setFlushMode
* @see org.hibernate.Session#setFlushMode
*/
protected FlushMode applyFlushMode(Session session, boolean existingTransaction) {
if (getFlushMode() == FLUSH_NEVER) {
if (existingTransaction) {
FlushMode previousFlushMode = session.getFlushMode();
if (!previousFlushMode.lessThan(FlushMode.COMMIT)) {
session.setFlushMode(FlushMode.MANUAL);
return previousFlushMode;
}
}
else {
session.setFlushMode(FlushMode.MANUAL);
}
}
else if (getFlushMode() == FLUSH_EAGER) {
if (existingTransaction) {
FlushMode previousFlushMode = session.getFlushMode();
if (!previousFlushMode.equals(FlushMode.AUTO)) {
session.setFlushMode(FlushMode.AUTO);
return previousFlushMode;
}
}
else {
// rely on default FlushMode.AUTO
}
}
else if (getFlushMode() == FLUSH_COMMIT) {
if (existingTransaction) {
FlushMode previousFlushMode = session.getFlushMode();
if (previousFlushMode.equals(FlushMode.AUTO) || previousFlushMode.equals(FlushMode.ALWAYS)) {
session.setFlushMode(FlushMode.COMMIT);
return previousFlushMode;
}
}
else {
session.setFlushMode(FlushMode.COMMIT);
}
}
else if (getFlushMode() == FLUSH_ALWAYS) {
if (existingTransaction) {
FlushMode previousFlushMode = session.getFlushMode();
if (!previousFlushMode.equals(FlushMode.ALWAYS)) {
session.setFlushMode(FlushMode.ALWAYS);
return previousFlushMode;
}
}
else {
session.setFlushMode(FlushMode.ALWAYS);
}
}
return null;
}
/**
* Flush the given Hibernate Session if necessary.
* @param session the current Hibernate Session
* @param existingTransaction if executing within an existing transaction
* @throws HibernateException in case of Hibernate flushing errors
*/
protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
logger.debug("Eagerly flushing Hibernate session");
session.flush();
}
}
/**
* Convert the given HibernateException to an appropriate exception
* from the {@code org.springframework.dao} hierarchy.
* <p>Will automatically apply a specified SQLExceptionTranslator to a
* Hibernate JDBCException, else rely on Hibernate's default translation.
* @param ex HibernateException that occured
* @return a corresponding DataAccessException
* @see SessionFactoryUtils#convertHibernateAccessException
* @see #setJdbcExceptionTranslator
*/
public DataAccessException convertHibernateAccessException(HibernateException ex) {
if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
}
else if (GenericJDBCException.class == ex.getClass()) {
return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
}
return SessionFactoryUtils.convertHibernateAccessException(ex);
}
/**
* Convert the given Hibernate JDBCException to an appropriate exception
* from the {@code org.springframework.dao} hierarchy, using the
* given SQLExceptionTranslator.
* @param ex Hibernate JDBCException that occured
* @param translator the SQLExceptionTranslator to use
* @return a corresponding DataAccessException
*/
protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
return translator.translate("Hibernate operation: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
}
/**
* Convert the given SQLException to an appropriate exception from the
* {@code org.springframework.dao} hierarchy. Can be overridden in subclasses.
* <p>Note that a direct SQLException can just occur when callback code
* performs direct JDBC access via {@code Session.connection()}.
* @param ex the SQLException
* @return the corresponding DataAccessException instance
* @see #setJdbcExceptionTranslator
*/
protected DataAccessException convertJdbcAccessException(SQLException ex) {
SQLExceptionTranslator translator = getJdbcExceptionTranslator();
if (translator == null) {
translator = getDefaultJdbcExceptionTranslator();
}
return translator.translate("Hibernate-related JDBC operation", null, ex);
}
/**
* Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
* <p>Creates a default
* {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
* for the SessionFactory's underlying DataSource.
*/
protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
if (this.defaultJdbcExceptionTranslator == null) {
this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
}
return this.defaultJdbcExceptionTranslator;
}
/**
* Enable the specified filters on the given Session.
* @param session the current Hibernate Session
* @see #setFilterNames
* @see org.hibernate.Session#enableFilter(String)
*/
protected void enableFilters(Session session) {
String[] filterNames = getFilterNames();
if (filterNames != null) {
for (String filterName : filterNames) {
session.enableFilter(filterName);
}
}
}
/**
* Disable the specified filters on the given Session.
* @param session the current Hibernate Session
* @see #setFilterNames
* @see org.hibernate.Session#disableFilter(String)
*/
protected void disableFilters(Session session) {
String[] filterNames = getFilterNames();
if (filterNames != null) {
for (String filterName : filterNames) {
session.disableFilter(filterName);
}
}
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* This interceptor binds a new Hibernate Session to the thread before a method
* call, closing and removing it afterwards in case of any method outcome.
* If there already is a pre-bound Session (e.g. from HibernateTransactionManager,
* or from a surrounding Hibernate-intercepted method), the interceptor simply
* participates in it.
*
* <p>Application code must retrieve a Hibernate Session via the
* {@code SessionFactoryUtils.getSession} method or - preferably -
* Hibernate's own {@code SessionFactory.getCurrentSession()} method, to be
* able to detect a thread-bound Session. Typically, the code will look like as follows:
*
* <pre class="code">
* public void doSomeDataAccessAction() {
* Session session = this.sessionFactory.getCurrentSession();
* ...
* // No need to close the Session or translate exceptions!
* }</pre>
*
* Note that this interceptor automatically translates HibernateExceptions,
* via delegating to the {@code SessionFactoryUtils.convertHibernateAccessException}
* method that converts them to exceptions that are compatible with the
* {@code org.springframework.dao} exception hierarchy (like HibernateTemplate does).
* This can be turned off if the raw exceptions are preferred.
*
* <p>This class can be considered a declarative alternative to HibernateTemplate's
* callback approach. The advantages are:
* <ul>
* <li>no anonymous classes necessary for callback implementations;
* <li>the possibility to throw any application exceptions from within data access code.
* </ul>
*
* <p>The drawback is the dependency on interceptor configuration. However, note
* that this interceptor is usually <i>not</i> necessary in scenarios where the
* data access code always executes within transactions. A transaction will always
* have a thread-bound Session in the first place, so adding this interceptor to the
* configuration just adds value when fine-tuning Session settings like the flush mode
* - or when relying on exception translation.
*
* @author Juergen Hoeller
* @since 1.2
* @see org.hibernate.SessionFactory#getCurrentSession()
* @see HibernateTransactionManager
* @see HibernateTemplate
* @deprecated as of Spring 3.2.7, in favor of either HibernateTemplate usage or
* native Hibernate API usage within transactions, in combination with a general
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}.
* Note: This class does not have an equivalent replacement in {@code orm.hibernate4}.
* If you desperately need a scoped Session bound through AOP, consider the newly
* introduced {@link org.springframework.orm.hibernate3.support.OpenSessionInterceptor}.
*/
@Deprecated
public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor {
private boolean exceptionConversionEnabled = true;
/**
* Set whether to convert any HibernateException raised to a Spring DataAccessException,
* compatible with the {@code org.springframework.dao} exception hierarchy.
* <p>Default is "true". Turn this flag off to let the caller receive raw exceptions
* as-is, without any wrapping.
* @see org.springframework.dao.DataAccessException
*/
public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) {
this.exceptionConversionEnabled = exceptionConversionEnabled;
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Session session = getSession();
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
boolean existingTransaction = (sessionHolder != null && sessionHolder.containsSession(session));
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateInterceptor");
}
else {
if (sessionHolder != null) {
sessionHolder.addSession(session);
}
else {
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
}
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(session);
Object retVal = methodInvocation.proceed();
flushIfNecessary(session, existingTransaction);
return retVal;
}
catch (HibernateException ex) {
if (this.exceptionConversionEnabled) {
throw convertHibernateAccessException(ex);
}
else {
throw ex;
}
}
finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateInterceptor");
disableFilters(session);
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
}
else {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
if (sessionHolder == null || sessionHolder.doesNotHoldNonDefaultSession()) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
}
}
}
/**
* Return a Session for use by this interceptor.
* @see SessionFactoryUtils#getSession
*/
protected Session getSession() {
return SessionFactoryUtils.getSession(
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
}
}

View File

@@ -1,128 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.util.JDBCExceptionReporter;
import org.springframework.jdbc.datasource.DataSourceUtils;
/**
* Hibernate connection provider for local DataSource instances
* in an application context. This provider will be used if
* LocalSessionFactoryBean's "dataSource" property is set
* without a Hibernate TransactionManagerLookup.
*
* @author Juergen Hoeller
* @since 1.2
* @see LocalSessionFactoryBean#setDataSource
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class LocalDataSourceConnectionProvider implements ConnectionProvider {
private DataSource dataSource;
private DataSource dataSourceToUse;
@Override
public void configure(Properties props) throws HibernateException {
this.dataSource = LocalSessionFactoryBean.getConfigTimeDataSource();
// absolutely needs thread-bound DataSource to initialize
if (this.dataSource == null) {
throw new HibernateException("No local DataSource found for configuration - " +
"'dataSource' property must be set on LocalSessionFactoryBean");
}
this.dataSourceToUse = getDataSourceToUse(this.dataSource);
}
/**
* Return the DataSource to use for retrieving Connections.
* <p>This implementation returns the passed-in DataSource as-is.
* @param originalDataSource the DataSource as configured by the user
* on LocalSessionFactoryBean
* @return the DataSource to actually retrieve Connections from
* (potentially wrapped)
* @see LocalSessionFactoryBean#setDataSource
*/
protected DataSource getDataSourceToUse(DataSource originalDataSource) {
return originalDataSource;
}
/**
* Return the DataSource that this ConnectionProvider wraps.
*/
public DataSource getDataSource() {
return this.dataSource;
}
/**
* This implementation delegates to the underlying DataSource.
* @see javax.sql.DataSource#getConnection()
*/
@Override
public Connection getConnection() throws SQLException {
try {
return this.dataSourceToUse.getConnection();
}
catch (SQLException ex) {
JDBCExceptionReporter.logExceptions(ex);
throw ex;
}
}
/**
* This implementation calls {@link DataSourceUtils#doCloseConnection},
* checking against a {@link org.springframework.jdbc.datasource.SmartDataSource}.
*/
@Override
public void closeConnection(Connection con) throws SQLException {
try {
DataSourceUtils.doCloseConnection(con, this.dataSourceToUse);
}
catch (SQLException ex) {
JDBCExceptionReporter.logExceptions(ex);
throw ex;
}
}
/**
* This implementation does nothing:
* We're dealing with an externally managed DataSource.
*/
@Override
public void close() {
}
/**
* This implementation returns {@code false}: We cannot guarantee
* to receive the same Connection within a transaction, not even when
* dealing with a JNDI DataSource.
*/
@Override
public boolean supportsAggressiveRelease() {
return false;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
/**
* Subclass of LocalDataSourceConnectionProvider that will be used
* if LocalSessionFactoryBean's "dataSource" property is set
* in combination with a Hibernate TransactionManagerLookup.
*
* @author Juergen Hoeller
* @since 2.5.1
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class LocalJtaDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
/**
* This implementation returns {@code true},
* since we're assuming a JTA DataSource.
*/
@Override
public boolean supportsAggressiveRelease() {
return true;
}
}

View File

@@ -1,122 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.Properties;
import org.hibernate.cache.CacheDataDescription;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.CollectionRegion;
import org.hibernate.cache.EntityRegion;
import org.hibernate.cache.QueryResultsRegion;
import org.hibernate.cache.RegionFactory;
import org.hibernate.cache.TimestampsRegion;
import org.hibernate.cache.access.AccessType;
import org.hibernate.cfg.Settings;
/**
* Proxy for a Hibernate RegionFactory, delegating to a Spring-managed
* RegionFactory instance, determined by LocalSessionFactoryBean's
* "cacheRegionFactory" property.
*
* @author Juergen Hoeller
* @since 3.0
* @see LocalSessionFactoryBean#setCacheRegionFactory
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class LocalRegionFactoryProxy implements RegionFactory {
private final RegionFactory regionFactory;
/**
* Standard constructor.
*/
public LocalRegionFactoryProxy() {
RegionFactory rf = (RegionFactory) LocalSessionFactoryBean.getConfigTimeRegionFactory();
// absolutely needs thread-bound RegionFactory to initialize
if (rf == null) {
throw new IllegalStateException("No Hibernate RegionFactory found - " +
"'cacheRegionFactory' property must be set on LocalSessionFactoryBean");
}
this.regionFactory = rf;
}
/**
* Properties constructor: not used by this class or formally required,
* but enforced by Hibernate when reflectively instantiating a RegionFactory.
*/
public LocalRegionFactoryProxy(Properties properties) {
this();
}
@Override
public void start(Settings settings, Properties properties) throws CacheException {
this.regionFactory.start(settings, properties);
}
@Override
public void stop() {
this.regionFactory.stop();
}
@Override
public boolean isMinimalPutsEnabledByDefault() {
return this.regionFactory.isMinimalPutsEnabledByDefault();
}
@Override
public AccessType getDefaultAccessType() {
return this.regionFactory.getDefaultAccessType();
}
@Override
public long nextTimestamp() {
return this.regionFactory.nextTimestamp();
}
@Override
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
return this.regionFactory.buildEntityRegion(regionName, properties, metadata);
}
@Override
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
CacheDataDescription metadata) throws CacheException {
return this.regionFactory.buildCollectionRegion(regionName, properties, metadata);
}
@Override
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties)
throws CacheException {
return this.regionFactory.buildQueryResultsRegion(regionName, properties);
}
@Override
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties)
throws CacheException {
return this.regionFactory.buildTimestampsRegion(regionName, properties);
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.Properties;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.hibernate.transaction.TransactionManagerLookup;
/**
* Implementation of Hibernate's {@link TransactionManagerLookup} interface
* that returns a Spring-managed JTA {@link TransactionManager}, determined
* by LocalSessionFactoryBean's "jtaTransactionManager" property.
*
* <p>The main advantage of this TransactionManagerLookup is that it avoids
* double configuration of JTA specifics. A single TransactionManager bean can
* be used for both JtaTransactionManager and LocalSessionFactoryBean, with no
* JTA setup in Hibernate configuration.
*
* <p>Alternatively, use Hibernate's own TransactionManagerLookup implementations:
* Spring's JtaTransactionManager only requires a TransactionManager for suspending
* and resuming transactions, so you might not need to apply such special Spring
* configuration at all.
*
* @author Juergen Hoeller
* @since 1.2
* @see LocalSessionFactoryBean#setJtaTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class LocalTransactionManagerLookup implements TransactionManagerLookup {
private final TransactionManager transactionManager;
public LocalTransactionManagerLookup() {
TransactionManager tm = LocalSessionFactoryBean.getConfigTimeTransactionManager();
// absolutely needs thread-bound TransactionManager to initialize
if (tm == null) {
throw new IllegalStateException("No JTA TransactionManager found - " +
"'jtaTransactionManager' property must be set on LocalSessionFactoryBean");
}
this.transactionManager = tm;
}
@Override
public TransactionManager getTransactionManager(Properties props) {
return this.transactionManager;
}
@Override
public String getUserTransactionName() {
return null;
}
@Override
public Object getTransactionIdentifier(Transaction transaction) {
return transaction;
}
}

View File

@@ -1,832 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.sql.DataSource;
import javax.transaction.Status;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.OptimisticLockException;
import org.hibernate.PersistentObjectException;
import org.hibernate.PessimisticLockException;
import org.hibernate.PropertyValueException;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.QueryTimeoutException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.DataException;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.SQLGrammarException;
import org.springframework.core.NamedThreadLocal;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
import org.springframework.transaction.jta.SpringJtaSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Helper class featuring methods for Hibernate Session handling,
* allowing for reuse of Hibernate Session instances within transactions.
* Also provides support for exception translation.
*
* <p>Supports synchronization with both Spring-managed JTA transactions
* (see {@link org.springframework.transaction.jta.JtaTransactionManager})
* and non-Spring JTA transactions (i.e. plain JTA or EJB CMT),
* transparently providing transaction-scoped Hibernate Sessions.
* Note that for non-Spring JTA transactions, a JTA TransactionManagerLookup
* has to be specified in the Hibernate configuration.
*
* <p>Used internally by {@link HibernateTemplate}, {@link HibernateInterceptor}
* and {@link HibernateTransactionManager}. Can also be used directly in
* application code.
*
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getSession
* @see #releaseSession
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public abstract class SessionFactoryUtils {
/**
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
* Returns {@code DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100}
* to execute Session cleanup before JDBC Connection cleanup, if any.
* @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
*/
public static final int SESSION_SYNCHRONIZATION_ORDER =
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
private static final ThreadLocal<Map<SessionFactory, Set<Session>>> deferredCloseHolder =
new NamedThreadLocal<Map<SessionFactory, Set<Session>>>("Hibernate Sessions registered for deferred close");
/**
* Determine the DataSource of the given SessionFactory.
* @param sessionFactory the SessionFactory to check
* @return the DataSource, or {@code null} if none found
* @see org.hibernate.engine.SessionFactoryImplementor#getConnectionProvider
* @see LocalDataSourceConnectionProvider
*/
public static DataSource getDataSource(SessionFactory sessionFactory) {
if (sessionFactory instanceof SessionFactoryImplementor) {
ConnectionProvider cp = ((SessionFactoryImplementor) sessionFactory).getConnectionProvider();
if (cp instanceof LocalDataSourceConnectionProvider) {
return ((LocalDataSourceConnectionProvider) cp).getDataSource();
}
}
return null;
}
/**
* Create an appropriate SQLExceptionTranslator for the given SessionFactory.
* If a DataSource is found, a SQLErrorCodeSQLExceptionTranslator for the DataSource
* is created; else, a SQLStateSQLExceptionTranslator as fallback.
* @param sessionFactory the SessionFactory to create the translator for
* @return the SQLExceptionTranslator
* @see #getDataSource
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
*/
public static SQLExceptionTranslator newJdbcExceptionTranslator(SessionFactory sessionFactory) {
DataSource ds = getDataSource(sessionFactory);
if (ds != null) {
return new SQLErrorCodeSQLExceptionTranslator(ds);
}
return new SQLStateSQLExceptionTranslator();
}
/**
* Try to retrieve the JTA TransactionManager from the given SessionFactory
* and/or Session. Check the passed-in SessionFactory for implementing
* SessionFactoryImplementor (the usual case), falling back to the
* SessionFactory reference that the Session itself carries.
* @param sessionFactory Hibernate SessionFactory
* @param session Hibernate Session (can also be {@code null})
* @return the JTA TransactionManager, if any
* @see javax.transaction.TransactionManager
* @see SessionFactoryImplementor#getTransactionManager
* @see Session#getSessionFactory
* @see org.hibernate.impl.SessionFactoryImpl
*/
public static TransactionManager getJtaTransactionManager(SessionFactory sessionFactory, Session session) {
SessionFactoryImplementor sessionFactoryImpl = null;
if (sessionFactory instanceof SessionFactoryImplementor) {
sessionFactoryImpl = ((SessionFactoryImplementor) sessionFactory);
}
else if (session != null) {
SessionFactory internalFactory = session.getSessionFactory();
if (internalFactory instanceof SessionFactoryImplementor) {
sessionFactoryImpl = (SessionFactoryImplementor) internalFactory;
}
}
return (sessionFactoryImpl != null ? sessionFactoryImpl.getTransactionManager() : null);
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using {@link HibernateTransactionManager}. Will create a new
* Session otherwise, if "allowCreate" is {@code true}.
* <p>This is the {@code getSession} method used by typical data access code,
* in combination with {@code releaseSession} called when done with
* the Session. Note that HibernateTemplate allows to write data access code
* without caring about such resource handling.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param allowCreate whether a non-transactional Session should be created
* when no transactional Session can be found for the current thread
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and
* "allowCreate" is {@code false}
* @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator)
* @see #releaseSession
* @see HibernateTemplate
*/
public static Session getSession(SessionFactory sessionFactory, boolean allowCreate)
throws DataAccessResourceFailureException, IllegalStateException {
try {
return doGetSession(sessionFactory, null, null, allowCreate);
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using {@link HibernateTransactionManager}. Will always create
* a new Session otherwise.
* <p>Supports setting a Session-level Hibernate entity interceptor that allows
* to inspect and change property values before writing to and reading from the
* database. Such an interceptor can also be set at the SessionFactory level
* (i.e. on LocalSessionFactoryBean), on HibernateTransactionManager, etc.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (may be {@code null}; only used
* when actually registering a transaction synchronization)
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @see LocalSessionFactoryBean#setEntityInterceptor
* @see HibernateTemplate#setEntityInterceptor
*/
public static Session getSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
try {
return doGetSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, true);
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using {@link HibernateTransactionManager}. Will create a new
* Session otherwise, if "allowCreate" is {@code true}.
* <p>Throws the original HibernateException, in contrast to {@link #getSession}.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param allowCreate whether a non-transactional Session should be created
* when no transactional Session can be found for the current thread
* @return the Hibernate Session
* @throws HibernateException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and allowCreate false
*/
public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate)
throws HibernateException, IllegalStateException {
return doGetSession(sessionFactory, null, null, allowCreate);
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using {@link HibernateTransactionManager}. Will create a new
* Session otherwise, if "allowCreate" is {@code true}.
* <p>Same as {@link #getSession}, but throwing the original HibernateException.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (may be {@code null})
* @param allowCreate whether a non-transactional Session should be created
* when no transactional Session can be found for the current thread
* @return the Hibernate Session
* @throws HibernateException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and
* "allowCreate" is {@code false}
*/
private static Session doGetSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
throws HibernateException, IllegalStateException {
Assert.notNull(sessionFactory, "No SessionFactory specified");
Object resource = TransactionSynchronizationManager.getResource(sessionFactory);
if (resource instanceof Session) {
return (Session) resource;
}
SessionHolder sessionHolder = (SessionHolder) resource;
if (sessionHolder != null && !sessionHolder.isEmpty()) {
// pre-bound Hibernate Session
Session session = null;
if (TransactionSynchronizationManager.isSynchronizationActive() &&
sessionHolder.doesNotHoldNonDefaultSession()) {
// Spring transaction management is active ->
// register pre-bound Session with it for transactional flushing.
session = sessionHolder.getValidatedSession();
if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {
logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
}
if (session != null) {
return session;
}
}
logger.debug("Opening Hibernate Session");
Session session = (entityInterceptor != null ?
sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());
// Use same Session for further Hibernate actions within the transaction.
// Thread object will get removed by synchronization at transaction completion.
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// We're within a Spring-managed transaction, possibly from JtaTransactionManager.
logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
SessionHolder holderToUse = sessionHolder;
if (holderToUse == null) {
holderToUse = new SessionHolder(session);
}
else {
holderToUse.addSession(session);
}
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != sessionHolder) {
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
}
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
}
// Check whether we are allowed to return the Session.
if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
closeSession(session);
throw new IllegalStateException("No Hibernate Session bound to thread, " +
"and configuration does not allow creation of non-transactional one here");
}
return session;
}
/**
* Retrieve a Session from the given SessionHolder, potentially from a
* JTA transaction synchronization.
* @param sessionHolder the SessionHolder to check
* @param sessionFactory the SessionFactory to get the JTA TransactionManager from
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (may be {@code null})
* @return the associated Session, if any
* @throws DataAccessResourceFailureException if the Session couldn't be created
*/
private static Session getJtaSynchronizedSession(
SessionHolder sessionHolder, SessionFactory sessionFactory,
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
// JTA synchronization is only possible with a javax.transaction.TransactionManager.
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
// in Hibernate configuration, it will contain a TransactionManager reference.
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
if (jtaTm != null) {
// Check whether JTA transaction management is active ->
// fetch pre-bound Session for the current JTA transaction, if any.
// (just necessary for JTA transaction suspension, with an individual
// Hibernate Session per currently active/suspended transaction)
try {
// Look for transaction-specific Session.
Transaction jtaTx = jtaTm.getTransaction();
if (jtaTx != null) {
int jtaStatus = jtaTx.getStatus();
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
Session session = sessionHolder.getValidatedSession(jtaTx);
if (session == null && !sessionHolder.isSynchronizedWithTransaction()) {
// No transaction-specific Session found: If not already marked as
// synchronized with transaction, register the default thread-bound
// Session as JTA-transactional. If there is no default Session,
// we're a new inner JTA transaction with an outer one being suspended:
// In that case, we'll return null to trigger opening of a new Session.
session = sessionHolder.getValidatedSession();
if (session != null) {
logger.debug("Registering JTA transaction synchronization for existing Hibernate Session");
sessionHolder.addSession(jtaTx, session);
jtaTx.registerSynchronization(
new SpringJtaSynchronizationAdapter(
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false),
jtaTm));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.NEVER, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT)) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
}
return session;
}
}
// No transaction active -> simply return default thread-bound Session, if any
// (possibly from OpenSessionInViewFilter/Interceptor).
return sessionHolder.getValidatedSession();
}
catch (Throwable ex) {
throw new DataAccessResourceFailureException("Could not check JTA transaction", ex);
}
}
else {
// No JTA TransactionManager -> simply return default thread-bound Session, if any
// (possibly from OpenSessionInViewFilter/Interceptor).
return sessionHolder.getValidatedSession();
}
}
/**
* Register a JTA synchronization for the given Session, if any.
* @param sessionHolder the existing thread-bound SessionHolder, if any
* @param session the Session to register
* @param sessionFactory the SessionFactory that the Session was created with
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (may be {@code null})
*/
private static void registerJtaSynchronization(Session session, SessionFactory sessionFactory,
SQLExceptionTranslator jdbcExceptionTranslator, SessionHolder sessionHolder) {
// JTA synchronization is only possible with a javax.transaction.TransactionManager.
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
// in Hibernate configuration, it will contain a TransactionManager reference.
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, session);
if (jtaTm != null) {
try {
Transaction jtaTx = jtaTm.getTransaction();
if (jtaTx != null) {
int jtaStatus = jtaTx.getStatus();
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
logger.debug("Registering JTA transaction synchronization for new Hibernate Session");
SessionHolder holderToUse = sessionHolder;
// Register JTA Transaction with existing SessionHolder.
// Create a new SessionHolder if none existed before.
if (holderToUse == null) {
holderToUse = new SessionHolder(jtaTx, session);
}
else {
holderToUse.addSession(jtaTx, session);
}
jtaTx.registerSynchronization(
new SpringJtaSynchronizationAdapter(
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true),
jtaTm));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != sessionHolder) {
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
}
}
}
}
catch (Throwable ex) {
throw new DataAccessResourceFailureException(
"Could not register synchronization with JTA TransactionManager", ex);
}
}
}
/**
* Get a new Hibernate Session from the given SessionFactory.
* Will return a new Session even if there already is a pre-bound
* Session for the given SessionFactory.
* <p>Within a transaction, this method will create a new Session
* that shares the transaction's JDBC Connection. More specifically,
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @return the new Session
*/
public static Session getNewSession(SessionFactory sessionFactory) {
return getNewSession(sessionFactory, null);
}
/**
* Get a new Hibernate Session from the given SessionFactory.
* Will return a new Session even if there already is a pre-bound
* Session for the given SessionFactory.
* <p>Within a transaction, this method will create a new Session
* that shares the transaction's JDBC Connection. More specifically,
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
* @return the new Session
*/
public static Session getNewSession(SessionFactory sessionFactory, Interceptor entityInterceptor) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
try {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && !sessionHolder.isEmpty()) {
if (entityInterceptor != null) {
return sessionFactory.openSession(sessionHolder.getAnySession().connection(), entityInterceptor);
}
else {
return sessionFactory.openSession(sessionHolder.getAnySession().connection());
}
}
else {
if (entityInterceptor != null) {
return sessionFactory.openSession(entityInterceptor);
}
else {
return sessionFactory.openSession();
}
}
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
/**
* Stringify the given Session for debug logging.
* Returns output equivalent to {@code Object.toString()}:
* the fully qualified class name + "@" + the identity hash code.
* <p>The sole reason why this is necessary is because Hibernate3's
* {@code Session.toString()} implementation is broken (and won't be fixed):
* it logs the toString representation of all persistent objects in the Session,
* which might lead to ConcurrentModificationExceptions if the persistent objects
* in turn refer to the Session (for example, for lazy loading).
* @param session the Hibernate Session to stringify
* @return the String representation of the given Session
*/
public static String toString(Session session) {
return session.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(session));
}
/**
* Return whether there is a transactional Hibernate Session for the current thread,
* that is, a Session bound to the current thread by Spring's transaction facilities.
* @param sessionFactory Hibernate SessionFactory to check (may be {@code null})
* @return whether there is a transactional Session for current thread
*/
public static boolean hasTransactionalSession(SessionFactory sessionFactory) {
if (sessionFactory == null) {
return false;
}
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
return (sessionHolder != null && !sessionHolder.isEmpty());
}
/**
* Return whether the given Hibernate Session is transactional, that is,
* bound to the current thread by Spring's transaction facilities.
* @param session the Hibernate Session to check
* @param sessionFactory Hibernate SessionFactory that the Session was created with
* (may be {@code null})
* @return whether the Session is transactional
*/
public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
if (sessionFactory == null) {
return false;
}
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
return (sessionHolder != null && sessionHolder.containsSession(session));
}
/**
* Apply the current transaction timeout, if any, to the given
* Hibernate Query object.
* @param query the Hibernate Query object
* @param sessionFactory Hibernate SessionFactory that the Query was created for
* (may be {@code null})
* @see org.hibernate.Query#setTimeout
*/
public static void applyTransactionTimeout(Query query, SessionFactory sessionFactory) {
Assert.notNull(query, "No Query object specified");
if (sessionFactory != null) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && sessionHolder.hasTimeout()) {
query.setTimeout(sessionHolder.getTimeToLiveInSeconds());
}
}
}
/**
* Apply the current transaction timeout, if any, to the given
* Hibernate Criteria object.
* @param criteria the Hibernate Criteria object
* @param sessionFactory Hibernate SessionFactory that the Criteria was created for
* @see org.hibernate.Criteria#setTimeout
*/
public static void applyTransactionTimeout(Criteria criteria, SessionFactory sessionFactory) {
Assert.notNull(criteria, "No Criteria object specified");
if (sessionFactory != null) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && sessionHolder.hasTimeout()) {
criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
}
}
}
/**
* Convert the given HibernateException to an appropriate exception
* from the {@code org.springframework.dao} hierarchy.
* @param ex HibernateException that occurred
* @return the corresponding DataAccessException instance
* @see HibernateAccessor#convertHibernateAccessException
* @see HibernateTransactionManager#convertHibernateAccessException
*/
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
if (ex instanceof JDBCConnectionException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof SQLGrammarException) {
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof QueryTimeoutException) {
QueryTimeoutException jdbcEx = (QueryTimeoutException) ex;
return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof LockAcquisitionException) {
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof PessimisticLockException) {
PessimisticLockException jdbcEx = (PessimisticLockException) ex;
return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof ConstraintViolationException) {
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
}
if (ex instanceof DataException) {
DataException jdbcEx = (DataException) ex;
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof JDBCException) {
return new HibernateJdbcException((JDBCException) ex);
}
// end of JDBCException (subclass) handling
if (ex instanceof QueryException) {
return new HibernateQueryException((QueryException) ex);
}
if (ex instanceof NonUniqueResultException) {
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
}
if (ex instanceof NonUniqueObjectException) {
return new DuplicateKeyException(ex.getMessage(), ex);
}
if (ex instanceof PropertyValueException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
if (ex instanceof PersistentObjectException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof TransientObjectException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof ObjectDeletedException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof UnresolvableObjectException) {
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
}
if (ex instanceof WrongClassException) {
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
}
if (ex instanceof StaleObjectStateException) {
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
}
if (ex instanceof StaleStateException) {
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
}
if (ex instanceof OptimisticLockException) {
return new HibernateOptimisticLockingFailureException((OptimisticLockException) ex);
}
// fallback
return new HibernateSystemException(ex);
}
/**
* Determine whether deferred close is active for the current thread
* and the given SessionFactory.
* @param sessionFactory the Hibernate SessionFactory to check
* @return whether deferred close is active
*/
public static boolean isDeferredCloseActive(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
return (holderMap != null && holderMap.containsKey(sessionFactory));
}
/**
* Initialize deferred close for the current thread and the given SessionFactory.
* Sessions will not be actually closed on close calls then, but rather at a
* {@link #processDeferredClose} call at a finishing point (like request completion).
* <p>Used by {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}
* and {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}
* when not configured for a single session.
* @param sessionFactory the Hibernate SessionFactory to initialize deferred close for
* @see #processDeferredClose
* @see #releaseSession
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter#setSingleSession
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor#setSingleSession
*/
public static void initDeferredClose(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
logger.debug("Initializing deferred close of Hibernate Sessions");
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
if (holderMap == null) {
holderMap = new HashMap<SessionFactory, Set<Session>>();
deferredCloseHolder.set(holderMap);
}
holderMap.put(sessionFactory, new LinkedHashSet<Session>(4));
}
/**
* Process all Hibernate Sessions that have been registered for deferred close
* for the given SessionFactory.
* @param sessionFactory the Hibernate SessionFactory to process deferred close for
* @see #initDeferredClose
* @see #releaseSession
*/
public static void processDeferredClose(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
if (holderMap == null || !holderMap.containsKey(sessionFactory)) {
throw new IllegalStateException("Deferred close not active for SessionFactory [" + sessionFactory + "]");
}
logger.debug("Processing deferred close of Hibernate Sessions");
Set<Session> sessions = holderMap.remove(sessionFactory);
for (Session session : sessions) {
closeSession(session);
}
if (holderMap.isEmpty()) {
deferredCloseHolder.remove();
}
}
/**
* Close the given Session, created via the given factory,
* if it is not managed externally (i.e. not bound to the thread).
* @param session the Hibernate Session to close (may be {@code null})
* @param sessionFactory Hibernate SessionFactory that the Session was created with
* (may be {@code null})
*/
public static void releaseSession(Session session, SessionFactory sessionFactory) {
if (session == null) {
return;
}
// Only close non-transactional Sessions.
if (!isSessionTransactional(session, sessionFactory)) {
closeSessionOrRegisterDeferredClose(session, sessionFactory);
}
}
/**
* Close the given Session or register it for deferred close.
* @param session the Hibernate Session to close
* @param sessionFactory Hibernate SessionFactory that the Session was created with
* (may be {@code null})
* @see #initDeferredClose
* @see #processDeferredClose
*/
static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) {
logger.debug("Registering Hibernate Session for deferred close");
// Switch Session to FlushMode.MANUAL for remaining lifetime.
session.setFlushMode(FlushMode.MANUAL);
Set<Session> sessions = holderMap.get(sessionFactory);
sessions.add(session);
}
else {
closeSession(session);
}
}
/**
* Perform actual closing of the Hibernate Session,
* catching and logging any cleanup exceptions thrown.
* @param session the Hibernate Session to close (may be {@code null})
* @see org.hibernate.Session#close()
*/
public static void closeSession(Session session) {
if (session != null) {
logger.debug("Closing Hibernate Session");
try {
session.close();
}
catch (HibernateException ex) {
logger.debug("Could not close Hibernate Session", ex);
}
catch (Throwable ex) {
logger.debug("Unexpected exception on closing Hibernate Session", ex);
}
}
}
}

View File

@@ -1,151 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
* HibernateTransactionManager binds instances of this class to the thread,
* for a given SessionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Juergen Hoeller
* @since 1.2
* @see HibernateTransactionManager
* @see SessionFactoryUtils
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class SessionHolder extends ResourceHolderSupport {
private static final Object DEFAULT_KEY = new Object();
/**
* This Map needs to be concurrent because there might be multi-threaded
* access in the case of JTA with remote transaction propagation.
*/
private final Map<Object, Session> sessionMap = new ConcurrentHashMap<Object, Session>(1);
private Transaction transaction;
private FlushMode previousFlushMode;
public SessionHolder(Session session) {
addSession(session);
}
public SessionHolder(Object key, Session session) {
addSession(key, session);
}
public Session getSession() {
return getSession(DEFAULT_KEY);
}
public Session getSession(Object key) {
return this.sessionMap.get(key);
}
public Session getValidatedSession() {
return getValidatedSession(DEFAULT_KEY);
}
public Session getValidatedSession(Object key) {
Session session = this.sessionMap.get(key);
// Check for dangling Session that's around but already closed.
// Effectively an assertion: that should never happen in practice.
// We'll seamlessly remove the Session here, to not let it cause
// any side effects.
if (session != null && !session.isOpen()) {
this.sessionMap.remove(key);
session = null;
}
return session;
}
public Session getAnySession() {
if (!this.sessionMap.isEmpty()) {
return this.sessionMap.values().iterator().next();
}
return null;
}
public void addSession(Session session) {
addSession(DEFAULT_KEY, session);
}
public void addSession(Object key, Session session) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(session, "Session must not be null");
this.sessionMap.put(key, session);
}
public Session removeSession(Object key) {
return this.sessionMap.remove(key);
}
public boolean containsSession(Session session) {
return this.sessionMap.containsValue(session);
}
public boolean isEmpty() {
return this.sessionMap.isEmpty();
}
public boolean doesNotHoldNonDefaultSession() {
return this.sessionMap.isEmpty() ||
(this.sessionMap.size() == 1 && this.sessionMap.containsKey(DEFAULT_KEY));
}
public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}
public Transaction getTransaction() {
return this.transaction;
}
public void setPreviousFlushMode(FlushMode previousFlushMode) {
this.previousFlushMode = previousFlushMode;
}
public FlushMode getPreviousFlushMode() {
return this.previousFlushMode;
}
@Override
public void clear() {
super.clear();
this.transaction = null;
this.previousFlushMode = null;
}
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import org.hibernate.HibernateException;
import org.hibernate.classic.Session;
import org.hibernate.context.CurrentSessionContext;
import org.hibernate.engine.SessionFactoryImplementor;
/**
* Implementation of Hibernate 3.1's CurrentSessionContext interface
* that delegates to Spring's SessionFactoryUtils for providing a
* Spring-managed current Session.
*
* <p>Used by Spring's {@link LocalSessionFactoryBean} when told to expose a
* transaction-aware SessionFactory. This is the default as of Spring 2.5.
*
* <p>This CurrentSessionContext implementation can also be specified in custom
* SessionFactory setup through the "hibernate.current_session_context_class"
* property, with the fully qualified name of this class as value.
*
* @author Juergen Hoeller
* @since 2.0
* @see SessionFactoryUtils#doGetSession
* @see LocalSessionFactoryBean#setExposeTransactionAwareSessionFactory
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class SpringSessionContext implements CurrentSessionContext {
private final SessionFactoryImplementor sessionFactory;
/**
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
* @param sessionFactory the SessionFactory to provide current Sessions for
*/
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Retrieve the Spring-managed Session for the current thread, if any.
*/
@Override
public Session currentSession() throws HibernateException {
try {
return (org.hibernate.classic.Session) SessionFactoryUtils.doGetSession(this.sessionFactory, false);
}
catch (IllegalStateException ex) {
throw new HibernateException(ex.getMessage());
}
}
}

View File

@@ -1,268 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.SessionImplementor;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Callback for resource cleanup at the end of a Spring-managed JTA transaction,
* that is, when participating in a JtaTransactionManager transaction.
*
* @author Juergen Hoeller
* @since 1.2
* @see SessionFactoryUtils
* @see org.springframework.transaction.jta.JtaTransactionManager
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
private final SessionHolder sessionHolder;
private final SessionFactory sessionFactory;
private final SQLExceptionTranslator jdbcExceptionTranslator;
private final boolean newSession;
/**
* Whether Hibernate has a looked-up JTA TransactionManager that it will
* automatically register CacheSynchronizations with on Session connect.
*/
private boolean hibernateTransactionCompletion = false;
private Transaction jtaTransaction;
private boolean holderActive = true;
public SpringSessionSynchronization(
SessionHolder sessionHolder, SessionFactory sessionFactory,
SQLExceptionTranslator jdbcExceptionTranslator, boolean newSession) {
this.sessionHolder = sessionHolder;
this.sessionFactory = sessionFactory;
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
this.newSession = newSession;
// Check whether the SessionFactory has a JTA TransactionManager.
TransactionManager jtaTm =
SessionFactoryUtils.getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
if (jtaTm != null) {
this.hibernateTransactionCompletion = true;
// Fetch current JTA Transaction object
// (just necessary for JTA transaction suspension, with an individual
// Hibernate Session per currently active/suspended transaction).
try {
this.jtaTransaction = jtaTm.getTransaction();
}
catch (SystemException ex) {
throw new DataAccessResourceFailureException("Could not access JTA transaction", ex);
}
}
}
/**
* Check whether there is a Hibernate Session for the current JTA
* transaction. Else, fall back to the default thread-bound Session.
*/
private Session getCurrentSession() {
Session session = null;
if (this.jtaTransaction != null) {
session = this.sessionHolder.getSession(this.jtaTransaction);
}
if (session == null) {
session = this.sessionHolder.getSession();
}
return session;
}
@Override
public int getOrder() {
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
}
@Override
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
getCurrentSession().disconnect();
}
}
@Override
public void resume() {
if (this.holderActive) {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
@Override
public void flush() {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
getCurrentSession().flush();
}
catch (HibernateException ex) {
throw translateException(ex);
}
}
@Override
public void beforeCommit(boolean readOnly) throws DataAccessException {
if (!readOnly) {
Session session = getCurrentSession();
// Read-write transaction -> flush the Hibernate Session.
// Further check: only flush when not FlushMode.NEVER/MANUAL.
if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
session.flush();
}
catch (HibernateException ex) {
throw translateException(ex);
}
}
}
}
private DataAccessException translateException(HibernateException ex) {
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
JDBCException jdbcEx = (JDBCException) ex;
return this.jdbcExceptionTranslator.translate(
"Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
}
return SessionFactoryUtils.convertHibernateAccessException(ex);
}
@Override
public void beforeCompletion() {
if (this.jtaTransaction != null) {
// Typically in case of a suspended JTA transaction:
// Remove the Session for the current JTA transaction, but keep the holder.
Session session = this.sessionHolder.removeSession(this.jtaTransaction);
if (session != null) {
if (this.sessionHolder.isEmpty()) {
// No Sessions for JTA transactions bound anymore -> could remove it.
TransactionSynchronizationManager.unbindResourceIfPossible(this.sessionFactory);
this.holderActive = false;
}
// Do not close a pre-bound Session. In that case, we'll find the
// transaction-specific Session the same as the default Session.
if (session != this.sessionHolder.getSession()) {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
}
else {
if (this.sessionHolder.getPreviousFlushMode() != null) {
// In case of pre-bound Session, restore previous flush mode.
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
}
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
session.disconnect();
}
return;
}
}
// We'll only get here if there was no specific JTA transaction to handle.
if (this.newSession) {
// Default behavior: unbind and close the thread-bound Hibernate Session.
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
this.holderActive = false;
if (this.hibernateTransactionCompletion) {
// Close the Hibernate Session here in case of a Hibernate TransactionManagerLookup:
// Hibernate will automatically defer the actual closing until JTA transaction completion.
// Else, the Session will be closed in the afterCompletion method, to provide the
// correct transaction status for releasing the Session's cache locks.
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(this.sessionHolder.getSession(), this.sessionFactory);
}
}
else {
Session session = this.sessionHolder.getSession();
if (this.sessionHolder.getPreviousFlushMode() != null) {
// In case of pre-bound Session, restore previous flush mode.
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
}
if (this.hibernateTransactionCompletion) {
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
// We know that this is appropriate if a TransactionManagerLookup has been specified.
session.disconnect();
}
}
}
@Override
public void afterCommit() {
}
@Override
public void afterCompletion(int status) {
try {
if (!this.hibernateTransactionCompletion || !this.newSession) {
// No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback.
// Always perform explicit afterTransactionCompletion callback for pre-bound Session,
// even with Hibernate TransactionManagerLookup (which only applies to new Sessions).
Session session = this.sessionHolder.getSession();
// Provide correct transaction status for releasing the Session's cache locks,
// if possible. Else, closing will release all cache locks assuming a rollback.
try {
if (session instanceof SessionImplementor) {
((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED, null);
}
}
finally {
// Close the Hibernate Session here if necessary
// (closed in beforeCompletion in case of TransactionManagerLookup).
if (this.newSession) {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
}
else if (!this.hibernateTransactionCompletion) {
session.disconnect();
}
}
}
if (!this.newSession && status != STATUS_COMMITTED) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
this.sessionHolder.getSession().clear();
}
}
finally {
if (this.sessionHolder.doesNotHoldNonDefaultSession()) {
this.sessionHolder.setSynchronizedWithTransaction(false);
}
}
}
}

View File

@@ -1,83 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.Properties;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Transaction;
import org.hibernate.jdbc.JDBCContext;
import org.hibernate.transaction.JDBCTransaction;
import org.hibernate.transaction.TransactionFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Spring-aware implementation of the Hibernate TransactionFactory interface, aware of
* Spring-synchronized transactions (in particular Spring-managed JTA transactions)
* and asking for default release mode ON_CLOSE. Otherwise identical to Hibernate's
* default {@link org.hibernate.transaction.JDBCTransactionFactory} implementation.
*
* @author Juergen Hoeller
* @since 2.5.4
* @see org.springframework.transaction.support.TransactionSynchronizationManager
* @see org.hibernate.transaction.JDBCTransactionFactory
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class SpringTransactionFactory implements TransactionFactory {
/**
* Sets connection release mode "on_close" as default.
* <p>This was the case for Hibernate 3.0; Hibernate 3.1 changed
* it to "auto" (i.e. "after_statement" or "after_transaction").
* However, for Spring's resource management (in particular for
* HibernateTransactionManager), "on_close" is the better default.
*/
@Override
public ConnectionReleaseMode getDefaultReleaseMode() {
return ConnectionReleaseMode.ON_CLOSE;
}
@Override
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext) {
return new JDBCTransaction(jdbcContext, transactionContext);
}
@Override
public void configure(Properties props) {
}
@Override
public boolean isTransactionManagerRequired() {
return false;
}
@Override
public boolean areCallbacksLocalToHibernateTransactions() {
return true;
}
@Override
public boolean isTransactionInProgress(
JDBCContext jdbcContext, Context transactionContext, Transaction transaction) {
return (transaction != null && transaction.isActive()) ||
TransactionSynchronizationManager.isActualTransactionActive();
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
/**
* Subclass of LocalDataSourceConnectionProvider that returns a
* transaction-aware proxy for the exposed DataSource. Used if
* LocalSessionFactoryBean's "useTransactionAwareDataSource" flag is on.
*
* @author Juergen Hoeller
* @since 1.2
* @see LocalSessionFactoryBean#setUseTransactionAwareDataSource
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class TransactionAwareDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
/**
* Return a TransactionAwareDataSourceProxy for the given DataSource,
* provided that it isn't a TransactionAwareDataSourceProxy already.
*/
@Override
protected DataSource getDataSourceToUse(DataSource originalDataSource) {
if (originalDataSource instanceof TransactionAwareDataSourceProxy) {
return originalDataSource;
}
return new TransactionAwareDataSourceProxy(originalDataSource);
}
/**
* This implementation returns {@code true}: We can guarantee
* to receive the same Connection within a transaction, as we are
* exposing a TransactionAwareDataSourceProxy.
*/
@Override
public boolean supportsAggressiveRelease() {
return true;
}
}

View File

@@ -1,133 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.util.Properties;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
/**
* Bean that encapsulates a Hibernate type definition.
*
* <p>Typically defined as inner bean within a LocalSessionFactoryBean
* definition, as list element for the "typeDefinitions" bean property.
* For example:
*
* <pre class="code">
* &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;
* ...
* &lt;property name="typeDefinitions"&gt;
* &lt;list&gt;
* &lt;bean class="org.springframework.orm.hibernate3.TypeDefinitionBean"&gt;
* &lt;property name="typeName" value="myType"/&gt;
* &lt;property name="typeClass" value="mypackage.MyTypeClass"/&gt;
* &lt;/bean&gt;
* &lt;/list&gt;
* &lt;/property&gt;
* ...
* &lt;/bean&gt;</pre>
*
* Alternatively, specify a bean id (or name) attribute for the inner bean,
* instead of the "typeName" property.
*
* @author Juergen Hoeller
* @since 1.2
* @see LocalSessionFactoryBean#setTypeDefinitions(TypeDefinitionBean[])
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class TypeDefinitionBean implements BeanNameAware, InitializingBean {
private String typeName;
private String typeClass;
private Properties parameters = new Properties();
/**
* Set the name of the type.
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
*/
public void setTypeName(String typeName) {
this.typeName = typeName;
}
/**
* Return the name of the type.
*/
public String getTypeName() {
return typeName;
}
/**
* Set the type implementation class.
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
*/
public void setTypeClass(String typeClass) {
this.typeClass = typeClass;
}
/**
* Return the type implementation class.
*/
public String getTypeClass() {
return typeClass;
}
/**
* Specify default parameters for the type.
* This only applies to parameterized types.
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
* @see org.hibernate.usertype.ParameterizedType
*/
public void setParameters(Properties parameters) {
this.parameters = parameters;
}
/**
* Return the default parameters for the type.
*/
public Properties getParameters() {
return parameters;
}
/**
* If no explicit type name has been specified, the bean name of
* the TypeDefinitionBean will be used.
* @see #setTypeName
*/
@Override
public void setBeanName(String name) {
if (this.typeName == null) {
this.typeName = name;
}
}
@Override
public void afterPropertiesSet() {
if (this.typeName == null) {
throw new IllegalArgumentException("typeName is required");
}
if (this.typeClass == null) {
throw new IllegalArgumentException("typeClass is required");
}
}
}

View File

@@ -1,228 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.annotation;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
/**
* Subclass of Spring's standard LocalSessionFactoryBean for Hibernate,
* supporting annotation metadata for mappings.
*
* <p>Example for an AnnotationSessionFactoryBean bean definition:
*
* <pre class="code">
* &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt;
* &lt;property name="dataSource" ref="dataSource"/&gt;
* &lt;property name="annotatedClasses"&gt;
* &lt;list&gt;
* &lt;value&gt;test.package.Foo&lt;/value&gt;
* &lt;value&gt;test.package.Bar&lt;/value&gt;
* &lt;/list&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* Or when using classpath scanning for autodetection of entity classes:
*
* <pre class="code">
* &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt;
* &lt;property name="dataSource" ref="dataSource"/&gt;
* &lt;property name="packagesToScan" value="test.package"/&gt;
* &lt;/bean&gt;</pre>
*
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
*
* @author Juergen Hoeller
* @since 1.2.2
* @see #setDataSource
* @see #setHibernateProperties
* @see #setAnnotatedClasses
* @see #setAnnotatedPackages
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class AnnotationSessionFactoryBean extends org.springframework.orm.hibernate3.LocalSessionFactoryBean
implements ResourceLoaderAware {
private static final String RESOURCE_PATTERN = "/**/*.class";
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
private Class<?>[] annotatedClasses;
private String[] annotatedPackages;
private String[] packagesToScan;
private TypeFilter[] entityTypeFilters = new TypeFilter[] {
new AnnotationTypeFilter(Entity.class, false),
new AnnotationTypeFilter(Embeddable.class, false),
new AnnotationTypeFilter(MappedSuperclass.class, false),
new AnnotationTypeFilter(org.hibernate.annotations.Entity.class, false)};
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
/**
* Specify annotated classes, for which mappings will be read from
* class-level annotation metadata.
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
*/
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
this.annotatedClasses = annotatedClasses;
}
/**
* Specify the names of annotated packages, for which package-level
* annotation metadata will be read.
* @see org.hibernate.cfg.Configuration#addPackage(String)
*/
public void setAnnotatedPackages(String... annotatedPackages) {
this.annotatedPackages = annotatedPackages;
}
/**
* Specify packages to search using Spring-based scanning for entity classes in
* the classpath. This is an alternative to listing annotated classes explicitly.
* <p>Default is none. Specify packages to search for autodetection of your entity
* classes in the classpath. This is analogous to Spring's component-scan feature
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
*/
public void setPackagesToScan(String... packagesToScan) {
this.packagesToScan = packagesToScan;
}
/**
* Specify custom type filters for Spring-based scanning for entity classes.
* <p>Default is to search all specified packages for classes annotated with
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
* or {@code @javax.persistence.MappedSuperclass}, as well as for
* Hibernate's special {@code @org.hibernate.annotations.Entity}.
* @see #setPackagesToScan
*/
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
this.entityTypeFilters = entityTypeFilters;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
/**
* Reads metadata from annotated classes and packages into the
* AnnotationConfiguration instance.
*/
@Override
protected void postProcessMappings(Configuration config) throws HibernateException {
if (this.annotatedClasses != null) {
for (Class<?> annotatedClass : this.annotatedClasses) {
config.addAnnotatedClass(annotatedClass);
}
}
if (this.annotatedPackages != null) {
for (String annotatedPackage : this.annotatedPackages) {
config.addPackage(annotatedPackage);
}
}
scanPackages(config);
}
/**
* Perform Spring-based scanning for entity classes.
* @see #setPackagesToScan
*/
protected void scanPackages(Configuration config) {
if (this.packagesToScan != null) {
Set<String> classNames = new TreeSet<String>();
Set<String> packageNames = new TreeSet<String>();
try {
for (String pkg : this.packagesToScan) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
if (matchesEntityTypeFilter(reader, readerFactory)) {
classNames.add(className);
}
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
}
}
}
}
}
catch (IOException ex) {
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
}
try {
for (String className : classNames) {
config.addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className));
}
for (String packageName : packageNames) {
config.addPackage(packageName);
}
}
catch (ClassNotFoundException ex) {
throw new MappingException("Failed to load annotated classes from classpath", ex);
}
}
}
/**
* Check whether any of the configured entity type filters matches
* the current class descriptor contained in the metadata reader.
*/
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
if (this.entityTypeFilters != null) {
for (TypeFilter filter : this.entityTypeFilters) {
if (filter.match(reader, readerFactory)) {
return true;
}
}
}
return false;
}
}

View File

@@ -1,5 +0,0 @@
/**
* Support package for the Hibernate 3 Annotation add-on,
* which supports JPA-compliant Java 5+ annotations for mappings.
*/
package org.springframework.orm.hibernate3.annotation;

View File

@@ -1,13 +0,0 @@
/**
* Package providing integration of
* <a href="http://www.hibernate.org">Hibernate 3.x</a>
* with Spring concepts.
*
* <p>Contains SessionFactory helper classes, a template plus callback
* for Hibernate access, and an implementation of Spring's transaction SPI
* for local Hibernate transactions.
*
* <p><b>This package supports Hibernate 3.x only.</b>
* See the {@code org.springframework.orm.hibernate4} package for Hibernate 4.x support.
*/
package org.springframework.orm.hibernate3;

View File

@@ -1,223 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.io.IOException;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.transaction.TransactionManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import org.hibernate.util.EqualsHelper;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobCreatorUtils;
import org.springframework.jdbc.support.lob.LobHandler;
/**
* Abstract base class for Hibernate UserType implementations that map to LOBs.
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
*
* <p>For writing LOBs, either an active Spring transaction synchronization
* or an active JTA transaction (with "jtaTransactionManager" specified on
* LocalSessionFactoryBean or a Hibernate TransactionManagerLookup configured
* through the corresponding Hibernate property) is required.
*
* <p>Offers template methods for setting parameters and getting result values,
* passing in the LobHandler or LobCreator to use.
*
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.jdbc.support.lob.LobHandler
* @see org.springframework.jdbc.support.lob.LobCreator
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setJtaTransactionManager
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public abstract class AbstractLobType implements UserType {
protected final Log logger = LogFactory.getLog(getClass());
private final LobHandler lobHandler;
private final TransactionManager jtaTransactionManager;
/**
* Constructor used by Hibernate: fetches config-time LobHandler and
* config-time JTA TransactionManager from LocalSessionFactoryBean.
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
*/
protected AbstractLobType() {
this(org.springframework.orm.hibernate3.LocalSessionFactoryBean.getConfigTimeLobHandler(),
org.springframework.orm.hibernate3.LocalSessionFactoryBean.getConfigTimeTransactionManager());
}
/**
* Constructor used for testing: takes an explicit LobHandler
* and an explicit JTA TransactionManager (can be {@code null}).
*/
protected AbstractLobType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
this.lobHandler = lobHandler;
this.jtaTransactionManager = jtaTransactionManager;
}
/**
* This implementation returns false.
*/
@Override
public boolean isMutable() {
return false;
}
/**
* This implementation delegates to the Hibernate EqualsHelper.
* @see org.hibernate.util.EqualsHelper#equals
*/
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return EqualsHelper.equals(x, y);
}
/**
* This implementation returns the hashCode of the given objectz.
*/
@Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
/**
* This implementation returns the passed-in value as-is.
*/
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
/**
* This implementation returns the passed-in value as-is.
*/
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
/**
* This implementation returns the passed-in value as-is.
*/
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
/**
* This implementation returns the passed-in original as-is.
*/
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
/**
* This implementation delegates to nullSafeGetInternal,
* passing in the LobHandler of this type.
* @see #nullSafeGetInternal
*/
@Override
@Deprecated
public final Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
if (this.lobHandler == null) {
throw new IllegalStateException("No LobHandler found for configuration - " +
"lobHandler property must be set on LocalSessionFactoryBean");
}
try {
return nullSafeGetInternal(rs, names, owner, this.lobHandler);
}
catch (IOException ex) {
throw new HibernateException("I/O errors during LOB access", ex);
}
}
/**
* This implementation delegates to nullSafeSetInternal,
* passing in a transaction-synchronized LobCreator for the
* LobHandler of this type.
* @see #nullSafeSetInternal
*/
@Override
@Deprecated
public final void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (this.lobHandler == null) {
throw new IllegalStateException("No LobHandler found for configuration - " +
"lobHandler property must be set on LocalSessionFactoryBean");
}
LobCreator lobCreator = this.lobHandler.getLobCreator();
try {
nullSafeSetInternal(st, index, value, lobCreator);
}
catch (IOException ex) {
throw new HibernateException("I/O errors during LOB access", ex);
}
LobCreatorUtils.registerTransactionSynchronization(lobCreator, this.jtaTransactionManager);
}
/**
* Template method to extract a value from the given result set.
* @param rs the ResultSet to extract from
* @param names the column names
* @param owner the containing entity
* @param lobHandler the LobHandler to use
* @return the extracted value
* @throws SQLException if thrown by JDBC methods
* @throws IOException if thrown by streaming methods
* @throws HibernateException in case of any other exceptions
*/
protected abstract Object nullSafeGetInternal(
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException, IOException, HibernateException;
/**
* Template method to set the given parameter value on the given statement.
* @param ps the PreparedStatement to set on
* @param index the statement parameter index
* @param value the value to set
* @param lobCreator the LobCreator to use
* @throws SQLException if thrown by JDBC methods
* @throws IOException if thrown by streaming methods
* @throws HibernateException in case of any other exceptions
*/
protected abstract void nullSafeSetInternal(
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, IOException, HibernateException;
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import javax.transaction.TransactionManager;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobHandler;
/**
* Hibernate UserType implementation for byte arrays that get mapped to BLOBs.
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
*
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
* work with most JDBC-compliant database drivers. In this case, the field type
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
* large enough binary type will work.
*
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class BlobByteArrayType extends AbstractLobType {
/**
* Constructor used by Hibernate: fetches config-time LobHandler and
* config-time JTA TransactionManager from LocalSessionFactoryBean.
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
*/
public BlobByteArrayType() {
super();
}
/**
* Constructor used for testing: takes an explicit LobHandler
* and an explicit JTA TransactionManager (can be {@code null}).
*/
protected BlobByteArrayType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
super(lobHandler, jtaTransactionManager);
}
@Override
public int[] sqlTypes() {
return new int[] {Types.BLOB};
}
@Override
public Class<?> returnedClass() {
return byte[].class;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public boolean equals(Object x, Object y) {
return (x == y) ||
(x instanceof byte[] && y instanceof byte[] && Arrays.equals((byte[]) x, (byte[]) y));
}
@Override
public Object deepCopy(Object value) {
if (value == null) {
return null;
}
byte[] original = (byte[]) value;
byte[] copy = new byte[original.length];
System.arraycopy(original, 0, copy, 0, original.length);
return copy;
}
@Override
protected Object nullSafeGetInternal(
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException {
return lobHandler.getBlobAsBytes(rs, names[0]);
}
@Override
protected void nullSafeSetInternal(
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException {
lobCreator.setBlobAsBytes(ps, index, (byte[]) value);
}
}

View File

@@ -1,171 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.transaction.TransactionManager;
import org.hibernate.HibernateException;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobHandler;
/**
* Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs.
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
*
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
* work with most JDBC-compliant database drivers. In this case, the field type
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
* large enough binary type will work.
*
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class BlobSerializableType extends AbstractLobType {
/**
* Initial size for ByteArrayOutputStreams used for serialization output.
* <p>If a serialized object is larger than these 1024 bytes, the size of
* the byte array used by the output stream will be doubled each time the
* limit is reached.
*/
private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024;
/**
* Constructor used by Hibernate: fetches config-time LobHandler and
* config-time JTA TransactionManager from LocalSessionFactoryBean.
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
*/
public BlobSerializableType() {
super();
}
/**
* Constructor used for testing: takes an explicit LobHandler
* and an explicit JTA TransactionManager (can be {@code null}).
*/
protected BlobSerializableType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
super(lobHandler, jtaTransactionManager);
}
@Override
public int[] sqlTypes() {
return new int[] {Types.BLOB};
}
@Override
public Class<?> returnedClass() {
return Serializable.class;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Object deepCopy(Object value) throws HibernateException {
try {
// Write to new byte array to clone.
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
ObjectOutputStream oos = new ObjectOutputStream(baos);
try {
oos.writeObject(value);
}
finally {
oos.close();
}
// Read it back and return a true copy.
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
try {
return ois.readObject();
}
finally {
ois.close();
}
}
catch (ClassNotFoundException ex) {
throw new HibernateException("Couldn't clone BLOB contents", ex);
}
catch (IOException ex) {
throw new HibernateException("Couldn't clone BLOB contents", ex);
}
}
@Override
protected Object nullSafeGetInternal(
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException, IOException, HibernateException {
InputStream is = lobHandler.getBlobAsBinaryStream(rs, names[0]);
if (is != null) {
ObjectInputStream ois = new ObjectInputStream(is);
try {
return ois.readObject();
}
catch (ClassNotFoundException ex) {
throw new HibernateException("Could not deserialize BLOB contents", ex);
}
finally {
ois.close();
}
}
else {
return null;
}
}
@Override
protected void nullSafeSetInternal(
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, IOException {
if (value != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
ObjectOutputStream oos = new ObjectOutputStream(baos);
try {
oos.writeObject(value);
oos.flush();
lobCreator.setBlobAsBytes(ps, index, baos.toByteArray());
}
finally {
oos.close();
}
}
else {
lobCreator.setBlobAsBytes(ps, index, null);
}
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.io.UnsupportedEncodingException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.transaction.TransactionManager;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobHandler;
/**
* Hibernate UserType implementation for Strings that get mapped to BLOBs.
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
*
* <p>This is intended for the (arguably unnatural, but still common) case
* where character data is stored in a binary LOB. This requires encoding
* and decoding the characters within this UserType; see the javadoc of the
* {@code getCharacterEncoding()} method.
*
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
* work with most JDBC-compliant database drivers. In this case, the field type
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
* large enough binary type will work.
*
* @author Juergen Hoeller
* @since 1.2.7
* @see #getCharacterEncoding()
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class BlobStringType extends AbstractLobType {
/**
* Constructor used by Hibernate: fetches config-time LobHandler and
* config-time JTA TransactionManager from LocalSessionFactoryBean.
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
*/
public BlobStringType() {
super();
}
/**
* Constructor used for testing: takes an explicit LobHandler
* and an explicit JTA TransactionManager (can be {@code null}).
*/
protected BlobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
super(lobHandler, jtaTransactionManager);
}
@Override
public int[] sqlTypes() {
return new int[] {Types.BLOB};
}
@Override
public Class<?> returnedClass() {
return String.class;
}
@Override
protected Object nullSafeGetInternal(
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException, UnsupportedEncodingException {
byte[] bytes = lobHandler.getBlobAsBytes(rs, names[0]);
if (bytes != null) {
String encoding = getCharacterEncoding();
return (encoding != null ? new String(bytes, encoding) : new String(bytes));
}
else {
return null;
}
}
@Override
protected void nullSafeSetInternal(
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, UnsupportedEncodingException {
if (value != null) {
String str = (String) value;
String encoding = getCharacterEncoding();
byte[] bytes = (encoding != null ? str.getBytes(encoding) : str.getBytes());
lobCreator.setBlobAsBytes(ps, index, bytes);
}
else {
lobCreator.setBlobAsBytes(ps, index, null);
}
}
/**
* Determine the character encoding to apply to the BLOB's bytes
* to turn them into a String.
* <p>Default is {@code null}, indicating to use the platform
* default encoding. To be overridden in subclasses for a specific
* encoding such as "ISO-8859-1" or "UTF-8".
* @return the character encoding to use, or {@code null}
* to use the platform default encoding
* @see String#String(byte[], String)
* @see String#getBytes(String)
*/
protected String getCharacterEncoding() {
return null;
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.transaction.TransactionManager;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobHandler;
/**
* Hibernate UserType implementation for Strings that get mapped to CLOBs.
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
*
* <p>Particularly useful for storing Strings with more than 4000 characters in an
* Oracle database (only possible via CLOBs), in combination with OracleLobHandler.
*
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
* work with most JDBC-compliant database drivers. In this case, the field type
* does not have to be CLOB: For databases like MySQL and MS SQL Server, any
* large enough character type will work.
*
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class ClobStringType extends AbstractLobType {
/**
* Constructor used by Hibernate: fetches config-time LobHandler and
* config-time JTA TransactionManager from LocalSessionFactoryBean.
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
*/
public ClobStringType() {
super();
}
/**
* Constructor used for testing: takes an explicit LobHandler
* and an explicit JTA TransactionManager (can be {@code null}).
*/
protected ClobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
super(lobHandler, jtaTransactionManager);
}
@Override
public int[] sqlTypes() {
return new int[] {Types.CLOB};
}
@Override
public Class<?> returnedClass() {
return String.class;
}
@Override
protected Object nullSafeGetInternal(
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException {
return lobHandler.getClobAsString(rs, names[0]);
}
@Override
protected void nullSafeSetInternal(
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException {
lobCreator.setClobAsString(ps, index, (String) value);
}
}

View File

@@ -1,216 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.support.DaoSupport;
/**
* Convenient super class for Hibernate-based data access objects.
*
* <p>Requires a {@link org.hibernate.SessionFactory} to be set, providing a
* {@link org.springframework.orm.hibernate3.HibernateTemplate} based on it to
* subclasses through the {@link #getHibernateTemplate()} method.
* Can alternatively be initialized directly with a HibernateTemplate,
* in order to reuse the latter's settings such as the SessionFactory,
* exception translator, flush mode, etc.
*
* <p>This base class is mainly intended for HibernateTemplate usage but can
* also be used when working with a Hibernate Session directly, for example
* when relying on transactional Sessions. Convenience {@link #getSession}
* and {@link #releaseSession} methods are provided for that usage style.
*
* <p>This class will create its own HibernateTemplate instance if a SessionFactory
* is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
* by default. A custom HibernateTemplate instance can be used through overriding
* {@link #createHibernateTemplate}.
*
* <p><b>NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
* also be coded in plain Hibernate style. Hence, for newly started projects,
* consider adopting the standard Hibernate3 style of coding data access objects
* instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.</b>
*
* @author Juergen Hoeller
* @since 1.2
* @see #setSessionFactory
* @see #getHibernateTemplate
* @see org.springframework.orm.hibernate3.HibernateTemplate
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public abstract class HibernateDaoSupport extends DaoSupport {
private org.springframework.orm.hibernate3.HibernateTemplate hibernateTemplate;
/**
* Set the Hibernate SessionFactory to be used by this DAO.
* Will automatically create a HibernateTemplate for the given SessionFactory.
* @see #createHibernateTemplate
* @see #setHibernateTemplate
*/
public final void setSessionFactory(SessionFactory sessionFactory) {
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
}
}
/**
* Create a HibernateTemplate for the given SessionFactory.
* Only invoked if populating the DAO with a SessionFactory reference!
* <p>Can be overridden in subclasses to provide a HibernateTemplate instance
* with different configuration, or a custom HibernateTemplate subclass.
* @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
* @return the new HibernateTemplate instance
* @see #setSessionFactory
*/
protected org.springframework.orm.hibernate3.HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
return new org.springframework.orm.hibernate3.HibernateTemplate(sessionFactory);
}
/**
* Return the Hibernate SessionFactory used by this DAO.
*/
public final SessionFactory getSessionFactory() {
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
}
/**
* Set the HibernateTemplate for this DAO explicitly,
* as an alternative to specifying a SessionFactory.
* @see #setSessionFactory
*/
public final void setHibernateTemplate(org.springframework.orm.hibernate3.HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
/**
* Return the HibernateTemplate for this DAO,
* pre-initialized with the SessionFactory or set explicitly.
* <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
* You may introspect its configuration, but not modify the configuration
* (other than from within an {@link #initDao} implementation).
* Consider creating a custom HibernateTemplate instance via
* {@code new HibernateTemplate(getSessionFactory())}, in which case
* you're allowed to customize the settings on the resulting instance.
*/
public final org.springframework.orm.hibernate3.HibernateTemplate getHibernateTemplate() {
return this.hibernateTemplate;
}
@Override
protected final void checkDaoConfig() {
if (this.hibernateTemplate == null) {
throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
}
}
/**
* Obtain a Hibernate Session, either from the current transaction or
* a new one. The latter is only allowed if the
* {@link org.springframework.orm.hibernate3.HibernateTemplate#setAllowCreate "allowCreate"}
* setting of this bean's {@link #setHibernateTemplate HibernateTemplate} is "true".
* <p><b>Note that this is not meant to be invoked from HibernateTemplate code
* but rather just in plain Hibernate code.</b> Either rely on a thread-bound
* Session or use it in combination with {@link #releaseSession}.
* <p>In general, it is recommended to use HibernateTemplate, either with
* the provided convenience operations or with a custom HibernateCallback
* that provides you with a Session to work on. HibernateTemplate will care
* for all resource management and for proper exception conversion.
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and allowCreate=false
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
*/
@Deprecated
protected final Session getSession() throws DataAccessResourceFailureException, IllegalStateException {
return getSession(this.hibernateTemplate.isAllowCreate());
}
/**
* Obtain a Hibernate Session, either from the current transaction or
* a new one. The latter is only allowed if "allowCreate" is true.
* <p><b>Note that this is not meant to be invoked from HibernateTemplate code
* but rather just in plain Hibernate code.</b> Either rely on a thread-bound
* Session or use it in combination with {@link #releaseSession}.
* <p>In general, it is recommended to use
* {@link #getHibernateTemplate() HibernateTemplate}, either with
* the provided convenience operations or with a custom
* {@link org.springframework.orm.hibernate3.HibernateCallback} that
* provides you with a Session to work on. HibernateTemplate will care
* for all resource management and for proper exception conversion.
* @param allowCreate if a non-transactional Session should be created when no
* transactional Session can be found for the current thread
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and allowCreate=false
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
*/
@Deprecated
protected final Session getSession(boolean allowCreate)
throws DataAccessResourceFailureException, IllegalStateException {
return (!allowCreate ?
org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(getSessionFactory(), false) :
org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(
getSessionFactory(),
this.hibernateTemplate.getEntityInterceptor(),
this.hibernateTemplate.getJdbcExceptionTranslator()));
}
/**
* Convert the given HibernateException to an appropriate exception from the
* {@code org.springframework.dao} hierarchy. Will automatically detect
* wrapped SQLExceptions and convert them accordingly.
* <p>Delegates to the
* {@link org.springframework.orm.hibernate3.HibernateTemplate#convertHibernateAccessException}
* method of this DAO's HibernateTemplate.
* <p>Typically used in plain Hibernate code, in combination with
* {@link #getSession} and {@link #releaseSession}.
* @param ex HibernateException that occurred
* @return the corresponding DataAccessException instance
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#convertHibernateAccessException
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
*/
@Deprecated
protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
return this.hibernateTemplate.convertHibernateAccessException(ex);
}
/**
* Close the given Hibernate Session, created via this DAO's SessionFactory,
* if it isn't bound to the thread (i.e. isn't a transactional Session).
* <p>Typically used in plain Hibernate code, in combination with
* {@link #getSession} and {@link #convertHibernateAccessException}.
* @param session the Session to close
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
*/
@Deprecated
protected final void releaseSession(Session session) {
org.springframework.orm.hibernate3.SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.io.Serializable;
import java.util.Map;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.event.MergeEvent;
import org.hibernate.event.def.DefaultMergeEventListener;
import org.hibernate.persister.entity.EntityPersister;
/**
* Extension of Hibernate's DefaultMergeEventListener, transferring the ids
* of newly saved objects to the corresponding original objects (that are part
* of the detached object graph passed into the {@code merge} method).
*
* <p>Transferring newly assigned ids to the original graph allows for continuing
* to use the original object graph, despite merged copies being registered with
* the current Hibernate Session. This is particularly useful for web applications
* that might want to store an object graph and then render it in a web view,
* with links that include the id of certain (potentially newly saved) objects.
*
* <p>The merge behavior given by this MergeEventListener is nearly identical
* to TopLink's merge behavior. See PetClinic for an example, which relies on
* ids being available for newly saved objects: the {@code HibernateClinic}
* and {@code TopLinkClinic} DAO implementations both use straight merge
* calls, with the Hibernate SessionFactory configuration specifying an
* {@code IdTransferringMergeEventListener}.
*
* <p>Typically specified as entry for LocalSessionFactoryBean's "eventListeners"
* map, with key "merge".
*
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setEventListeners(java.util.Map)
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings({"serial", "rawtypes"})
public class IdTransferringMergeEventListener extends DefaultMergeEventListener {
/**
* Hibernate 3.1 implementation of ID transferral.
*/
@Override
protected void entityIsTransient(MergeEvent event, Map copyCache) {
super.entityIsTransient(event, copyCache);
SessionImplementor session = event.getSession();
EntityPersister persister = session.getEntityPersister(event.getEntityName(), event.getEntity());
// Extract id from merged copy (which is currently registered with Session).
Serializable id = persister.getIdentifier(event.getResult(), session.getEntityMode());
// Set id on original object (which remains detached).
persister.setIdentifier(event.getOriginal(), id, session.getEntityMode());
}
}

View File

@@ -1,324 +0,0 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Servlet Filter that binds a Hibernate Session to the thread for the entire
* processing of the request. Intended for the "Open Session in View" pattern,
* i.e. to allow for lazy loading in web views despite the original transactions
* already being completed.
*
* <p>This filter makes Hibernate Sessions available via the current thread, which
* will be autodetected by transaction managers. It is suitable for service layer
* transactions via {@link org.springframework.orm.hibernate3.HibernateTransactionManager}
* or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
* as for non-transactional execution (if configured appropriately).
*
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
* with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used
* in combination with service layer transactions that care for the flushing: The
* active transaction manager will temporarily change the flush mode to
* {@code FlushMode.AUTO} during a read-write transaction, with the flush
* mode reset to {@code FlushMode.NEVER} at the end of each transaction.
* If you intend to use this filter without transactions, consider changing
* the default flush mode (through the "flushMode" property).
*
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
* have not appeared before, through the use of a single Hibernate Session for the
* processing of an entire request. In particular, the reassociation of persistent
* objects with a Hibernate Session has to occur at the very beginning of request
* processing, to avoid clashes with already loaded instances of the same objects.
*
* <p>Alternatively, turn this filter into deferred close mode, by specifying
* "singleSession"="false": It will not use a single session per request then,
* but rather let each data access operation or transaction use its own session
* (like without Open Session in View). Each of those sessions will be registered
* for deferred close, though, actually processed at request completion.
*
* <p>A single session per request allows for most efficient first-level caching,
* but can cause side effects, for example on {@code saveOrUpdate} or when
* continuing after a rolled-back transaction. The deferred close strategy is as safe
* as no Open Session in View in that respect, while still allowing for lazy loading
* in views (but not providing a first-level cache for the entire request).
*
* <p>Looks up the SessionFactory in Spring's root web application context.
* Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml};
* the default bean name is "sessionFactory".
*
* @author Juergen Hoeller
* @since 1.2
* @see #setSingleSession
* @see #setFlushMode
* @see #lookupSessionFactory
* @see OpenSessionInViewInterceptor
* @see OpenSessionInterceptor
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
* @see org.springframework.transaction.support.TransactionSynchronizationManager
* @see org.hibernate.SessionFactory#getCurrentSession()
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class OpenSessionInViewFilter extends OncePerRequestFilter {
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
private boolean singleSession = true;
private FlushMode flushMode = FlushMode.MANUAL;
/**
* Set the bean name of the SessionFactory to fetch from Spring's
* root application context. Default is "sessionFactory".
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
*/
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
this.sessionFactoryBeanName = sessionFactoryBeanName;
}
/**
* Return the bean name of the SessionFactory to fetch from Spring's
* root application context.
*/
protected String getSessionFactoryBeanName() {
return this.sessionFactoryBeanName;
}
/**
* Set whether to use a single session for each request. Default is "true".
* <p>If set to "false", each data access operation or transaction will use
* its own session (like without Open Session in View). Each of those
* sessions will be registered for deferred close, though, actually
* processed at request completion.
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#initDeferredClose
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#processDeferredClose
*/
public void setSingleSession(boolean singleSession) {
this.singleSession = singleSession;
}
/**
* Return whether to use a single session for each request.
*/
protected boolean isSingleSession() {
return this.singleSession;
}
/**
* Specify the Hibernate FlushMode to apply to this filter's
* {@link org.hibernate.Session}. Only applied in single session mode.
* <p>Can be populated with the corresponding constant name in XML bean
* definitions: e.g. "AUTO".
* <p>The default is "MANUAL". Specify "AUTO" if you intend to use
* this filter without service layer transactions.
* @see org.hibernate.Session#setFlushMode
* @see org.hibernate.FlushMode#MANUAL
* @see org.hibernate.FlushMode#AUTO
*/
public void setFlushMode(FlushMode flushMode) {
this.flushMode = flushMode;
}
/**
* Return the Hibernate FlushMode that this filter applies to its
* {@link org.hibernate.Session} (in single session mode).
*/
protected FlushMode getFlushMode() {
return this.flushMode;
}
/**
* Returns "false" so that the filter may re-bind the opened Hibernate
* {@code Session} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
/**
* Returns "false" so that the filter may provide a Hibernate
* {@code Session} to each error dispatches.
*/
@Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
String key = getAlreadyFilteredAttributeName();
if (isSingleSession()) {
// single session mode
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
}
else {
boolean isFirstRequest = !isAsyncDispatch(request);
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
Session session = getSession(sessionFactory);
org.springframework.orm.hibernate3.SessionHolder sessionHolder = new org.springframework.orm.hibernate3.SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
}
}
else {
// deferred close mode
Assert.state(!isAsyncStarted(request), "Deferred close mode is not supported on async dispatches");
if (org.springframework.orm.hibernate3.SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
// Do not modify deferred close: just set the participate flag.
participate = true;
}
else {
org.springframework.orm.hibernate3.SessionFactoryUtils.initDeferredClose(sessionFactory);
}
}
try {
filterChain.doFilter(request, response);
}
finally {
if (!participate) {
if (isSingleSession()) {
// single session mode
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (!isAsyncStarted(request)) {
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
closeSession(sessionHolder.getSession(), sessionFactory);
}
}
else {
// deferred close mode
org.springframework.orm.hibernate3.SessionFactoryUtils.processDeferredClose(sessionFactory);
}
}
}
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
* variant without arguments.
* @param request the current request
* @return the SessionFactory to use
*/
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
return lookupSessionFactory();
}
/**
* Look up the SessionFactory that this filter should use.
* <p>The default implementation looks for a bean with the specified name
* in Spring's root application context.
* @return the SessionFactory to use
* @see #getSessionFactoryBeanName
*/
protected SessionFactory lookupSessionFactory() {
if (logger.isDebugEnabled()) {
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
}
/**
* Get a Session for the SessionFactory that this filter uses.
* Note that this just applies in single session mode!
* <p>The default implementation delegates to the
* {@code SessionFactoryUtils.getSession} method and
* sets the {@code Session}'s flush mode to "MANUAL".
* <p>Can be overridden in subclasses for creating a Session with a
* custom entity interceptor or JDBC exception translator.
* @param sessionFactory the SessionFactory that this filter uses
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
* @see org.hibernate.FlushMode#MANUAL
*/
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(sessionFactory, true);
FlushMode flushMode = getFlushMode();
if (flushMode != null) {
session.setFlushMode(flushMode);
}
return session;
}
/**
* Close the given Session.
* Note that this just applies in single session mode!
* <p>Can be overridden in subclasses, e.g. for flushing the Session before
* closing it. See class-level javadoc for a discussion of flush handling.
* Note that you should also override getSession accordingly, to set
* the flush mode to something else than NEVER.
* @param session the Session used for filtering
* @param sessionFactory the SessionFactory that this filter uses
*/
protected void closeSession(Session session, SessionFactory sessionFactory) {
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(session);
}
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
}

View File

@@ -1,277 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
/**
* Spring web request interceptor that binds a Hibernate {@code Session} to the
* thread for the entire processing of the request.
*
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
* is a pattern that allows for the lazy loading of associations in web views despite
* the original transactions already being completed.
*
* <p>This interceptor makes Hibernate {@code Sessions} available via the current
* thread, which will be autodetected by transaction managers. It is suitable for
* service layer transactions via
* {@link org.springframework.orm.hibernate3.HibernateTransactionManager} or
* {@link org.springframework.transaction.jta.JtaTransactionManager} as well as for
* non-transactional execution (if configured appropriately).
*
* <p><b>NOTE</b>: This interceptor will by default <i>not</i> flush the Hibernate
* {@code Session}, with the flush mode being set to {@code FlushMode.NEVER}.
* It assumes that it will be used in combination with service layer transactions
* that handle the flushing: the active transaction manager will temporarily change
* the flush mode to {@code FlushMode.AUTO} during a read-write transaction,
* with the flush mode reset to {@code FlushMode.NEVER} at the end of each
* transaction. If you intend to use this interceptor without transactions, consider
* changing the default flush mode (through the
* {@link #setFlushMode(int) "flushMode"} property).
*
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is
* configured in a Spring application context and can thus take advantage of bean
* wiring. It inherits common Hibernate configuration properties from
* {@link org.springframework.orm.hibernate3.HibernateAccessor},
* to be configured in a bean definition.
*
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
* that have not appeared before, through the use of a single Hibernate
* {@code Session} for the processing of an entire request. In particular, the
* reassociation of persistent objects with a Hibernate {@code Session} has to
* occur at the very beginning of request processing, to avoid clashes with already
* loaded instances of the same objects.
*
* <p>Alternatively, turn this interceptor into deferred close mode, by specifying
* "singleSession"="false": It will not use a single session per request then,
* but rather let each data access operation or transaction use its own session
* (as would be the case without Open Session in View). Each of those sessions will
* be registered for deferred close though, which will actually be processed at
* request completion.
*
* <p>A single session per request allows for the most efficient first-level caching,
* but can cause side effects, for example on {@code saveOrUpdate} or when
* continuing after a rolled-back transaction. The deferred close strategy is as safe
* as no Open Session in View in that respect, while still allowing for lazy loading
* in views (but not providing a first-level cache for the entire request).
*
* @author Juergen Hoeller
* @since 1.2
* @see #setSingleSession
* @see #setFlushMode
* @see OpenSessionInViewFilter
* @see OpenSessionInterceptor
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
* @see org.springframework.transaction.support.TransactionSynchronizationManager
* @see org.hibernate.SessionFactory#getCurrentSession()
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class OpenSessionInViewInterceptor extends org.springframework.orm.hibernate3.HibernateAccessor implements AsyncWebRequestInterceptor {
/**
* Suffix that gets appended to the {@code SessionFactory}
* {@code toString()} representation for the "participate in existing
* session handling" request attribute.
* @see #getParticipateAttributeName
*/
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
private boolean singleSession = true;
/**
* Create a new {@code OpenSessionInViewInterceptor},
* turning the default flushMode to {@code FLUSH_NEVER}.
* @see #setFlushMode
*/
public OpenSessionInViewInterceptor() {
setFlushMode(FLUSH_NEVER);
}
/**
* Set whether to use a single session for each request. Default is "true".
* <p>If set to false, each data access operation or transaction will use
* its own session (like without Open Session in View). Each of those
* sessions will be registered for deferred close, though, actually
* processed at request completion.
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#initDeferredClose
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#processDeferredClose
*/
public void setSingleSession(boolean singleSession) {
this.singleSession = singleSession;
}
/**
* Return whether to use a single session for each request.
*/
protected boolean isSingleSession() {
return singleSession;
}
/**
* Open a new Hibernate {@code Session} according to the settings of this
* {@code HibernateAccessor} and bind it to the thread via the
* {@link TransactionSynchronizationManager}.
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
*/
@Override
public void preHandle(WebRequest request) throws DataAccessException {
String participateAttributeName = getParticipateAttributeName();
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
if (asyncManager.hasConcurrentResult()) {
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
return;
}
}
if ((isSingleSession() && TransactionSynchronizationManager.hasResource(getSessionFactory())) ||
org.springframework.orm.hibernate3.SessionFactoryUtils.isDeferredCloseActive(getSessionFactory())) {
// Do not modify the Session: just mark the request accordingly.
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
int newCount = (count != null ? count + 1 : 1);
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
}
else {
if (isSingleSession()) {
// single session mode
logger.debug("Opening single Hibernate Session in OpenSessionInViewInterceptor");
Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
applyFlushMode(session, false);
org.springframework.orm.hibernate3.SessionHolder sessionHolder = new org.springframework.orm.hibernate3.SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
AsyncRequestInterceptor asyncRequestInterceptor =
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
}
else {
// deferred close mode
org.springframework.orm.hibernate3.SessionFactoryUtils.initDeferredClose(getSessionFactory());
}
}
}
/**
* Flush the Hibernate {@code Session} before view rendering, if necessary.
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
* <p>The default is {@code FLUSH_NEVER} to avoid this extra flushing,
* assuming that service layer transactions have flushed their changes on commit.
* @see #setFlushMode
*/
@Override
public void postHandle(WebRequest request, ModelMap model) throws DataAccessException {
if (isSingleSession()) {
// Only potentially flush in single session mode.
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
logger.debug("Flushing single Hibernate Session in OpenSessionInViewInterceptor");
try {
flushIfNecessary(sessionHolder.getSession(), false);
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
}
}
/**
* Unbind the Hibernate {@code Session} from the thread and close it (in
* single session mode), or process deferred close for all sessions that have
* been opened during the current request (in deferred close mode).
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
@Override
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
if (!decrementParticipateCount(request)) {
if (isSingleSession()) {
// single session mode
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
logger.debug("Closing single Hibernate Session in OpenSessionInViewInterceptor");
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
else {
// deferred close mode
org.springframework.orm.hibernate3.SessionFactoryUtils.processDeferredClose(getSessionFactory());
}
}
}
@Override
public void afterConcurrentHandlingStarted(WebRequest request) {
if (!decrementParticipateCount(request)) {
if (isSingleSession()) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
else {
throw new IllegalStateException("Deferred close mode is not supported with async requests.");
}
}
}
private boolean decrementParticipateCount(WebRequest request) {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
if (count == null) {
return false;
}
// Do not modify the Session: just clear the marker.
if (count > 1) {
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
}
else {
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
}
return true;
}
/**
* Return the name of the request attribute that identifies that a request is
* already intercepted.
* <p>The default implementation takes the {@code toString()} representation
* of the {@code SessionFactory} instance and appends {@link #PARTICIPATE_SUFFIX}.
*/
protected String getParticipateAttributeName() {
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
import org.hibernate.EmptyInterceptor;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.aop.support.AopUtils;
/**
* Hibernate3 interceptor used for getting the proper entity name for scoped
* beans. As scoped bean classes are proxies generated at runtime, they are
* unrecognized by the persisting framework. Using this interceptor, the
* original scoped bean class is retrieved end exposed to Hibernate for
* persisting.
*
* <p>Usage example:
*
* <pre class="code">
* &lt;bean id=&quot;sessionFactory&quot; class=&quot;org.springframework.orm.hibernate3.LocalSessionFactoryBean&quot;&gt;
* ...
* &lt;property name=&quot;entityInterceptor&quot;&gt;
* &lt;bean class=&quot;org.springframework.orm.hibernate3.support.ScopedBeanInterceptor&quot;/&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class ScopedBeanInterceptor extends EmptyInterceptor {
@Override
public String getEntityName(Object entity) {
if (entity instanceof ScopedObject) {
// Determine underlying object's type.
Object targetObject = ((ScopedObject) entity).getTargetObject();
return AopUtils.getTargetClass(targetObject).getName();
}
// Any other object: delegate to the default implementation.
return super.getEntityName(entity);
}
}

View File

@@ -1,5 +0,0 @@
/**
* Classes supporting the {@code org.springframework.orm.hibernate3} package.
* Contains a DAO base class for HibernateTemplate usage.
*/
package org.springframework.orm.hibernate3.support;

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import org.hibernate.TransactionException;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.springframework.transaction.jta.UserTransactionAdapter;
import org.springframework.util.Assert;
/**
* Implementation of Hibernate 5's JtaPlatform SPI, exposing passed-in {@link TransactionManager},
* {@link UserTransaction} and {@link TransactionSynchronizationRegistry} references.
*
* @author Juergen Hoeller
* @since 4.2
*/
@SuppressWarnings("serial")
class ConfigurableJtaPlatform implements JtaPlatform {
private final TransactionManager transactionManager;
private final UserTransaction userTransaction;
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
/**
* Create a new ConfigurableJtaPlatform instance with the given
* JTA TransactionManager and optionally a given UserTransaction.
* @param tm the JTA TransactionManager reference (required)
* @param ut the JTA UserTransaction reference (optional)
* @param tsr the JTA 1.1 TransactionSynchronizationRegistry (optional)
*/
public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut, TransactionSynchronizationRegistry tsr) {
Assert.notNull(tm, "TransactionManager reference must not be null");
this.transactionManager = tm;
this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
this.transactionSynchronizationRegistry = tsr;
}
@Override
public TransactionManager retrieveTransactionManager() {
return this.transactionManager;
}
@Override
public UserTransaction retrieveUserTransaction() {
return this.userTransaction;
}
@Override
public Object getTransactionIdentifier(Transaction transaction) {
return transaction;
}
@Override
public boolean canRegisterSynchronization() {
try {
return (this.transactionManager.getStatus() == Status.STATUS_ACTIVE);
}
catch (SystemException ex) {
throw new TransactionException("Could not determine JTA transaction status", ex);
}
}
@Override
public void registerSynchronization(Synchronization synchronization) {
if (this.transactionSynchronizationRegistry != null) {
this.transactionSynchronizationRegistry.registerInterposedSynchronization(synchronization);
}
else {
try {
this.transactionManager.getTransaction().registerSynchronization(synchronization);
}
catch (Exception ex) {
throw new TransactionException("Could not access JTA Transaction to register synchronization", ex);
}
}
}
@Override
public int getCurrentStatus() throws SystemException {
return this.transactionManager.getStatus();
}
}

View File

@@ -14,9 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
import java.sql.SQLException;
package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
import org.hibernate.Session;
@@ -25,35 +23,19 @@ import org.hibernate.Session;
* Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
* execution methods, often as anonymous classes within a method implementation.
* A typical implementation will call {@code Session.load/find/update} to perform
* some operations on persistent objects. It can also perform direct JDBC operations
* via Hibernate's {@code Session.connection()}, operating on a JDBC Connection.
*
* <p>Note that Hibernate works on unmodified plain Java objects, performing dirty
* detection via copies made at load time. Returned objects can thus be used outside
* of an active Hibernate Session without any hassle, e.g. for display in a web GUI.
* Reassociating such instances with a new Session, e.g. for updates when coming
* back from the GUI, is straightforward, as the instance has kept its identity.
* You should care to reassociate them as early as possible though, to avoid having
* already loaded a version from the database in the same Session.
* some operations on persistent objects.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see HibernateTemplate
* @see HibernateTransactionManager
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public interface HibernateCallback<T> {
/**
* Gets called by {@code HibernateTemplate.execute} with an active
* Hibernate {@code Session}. Does not need to care about activating
* or closing the {@code Session}, or handling transactions.
* <p>If called without a thread-bound Hibernate transaction (initiated
* by HibernateTransactionManager), the code will simply get executed on the
* underlying JDBC connection with its transactional semantics. If Hibernate
* is configured to use a JTA-aware DataSource, the JDBC connection and thus
* the callback code will be transactional if a JTA transaction is active.
* <p>Allows for returning a result object created within the callback,
* i.e. a domain object or a collection of domain objects.
* A thrown custom RuntimeException is treated as an application exception:
@@ -61,10 +43,8 @@ public interface HibernateCallback<T> {
* @param session active Hibernate session
* @return a result object, or {@code null} if none
* @throws HibernateException if thrown by the Hibernate API
* @throws SQLException if thrown by Hibernate-exposed JDBC API
* @see HibernateTemplate#execute
* @see HibernateTemplate#executeFind
*/
T doInHibernate(Session session) throws HibernateException, SQLException;
T doInHibernate(Session session) throws HibernateException;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,12 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
/**
* {@link PersistenceExceptionTranslator} capable of translating {@link HibernateException}
@@ -34,37 +32,12 @@ import org.springframework.jdbc.support.SQLExceptionTranslator;
* of this type must be registered manually.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 3.1
* @since 4.2
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
* @see SessionFactoryUtils#convertHibernateAccessException(HibernateException)
* @see SQLExceptionTranslator
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {
private SQLExceptionTranslator jdbcExceptionTranslator;
/**
* Set the JDBC exception translator for the SessionFactory,
* exposed via the PersistenceExceptionTranslator interface.
* <p>Applied to any SQLException root cause of a Hibernate JDBCException,
* overriding Hibernate's default SQLException translation (which is
* based on Hibernate's Dialect for a specific target database).
* @param jdbcExceptionTranslator the exception translator
* @see java.sql.SQLException
* @see org.hibernate.JDBCException
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
* @see org.springframework.dao.support.PersistenceExceptionTranslator
*/
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
if (ex instanceof HibernateException) {
@@ -76,19 +49,11 @@ public class HibernateExceptionTranslator implements PersistenceExceptionTransla
/**
* Convert the given HibernateException to an appropriate exception from the
* {@code org.springframework.dao} hierarchy.
* <p>Will automatically apply a specified SQLExceptionTranslator to a
* Hibernate JDBCException, else rely on Hibernate's default translation.
* @param ex HibernateException that occured
* @return a corresponding DataAccessException
* @see SessionFactoryUtils#convertHibernateAccessException
* @see #setJdbcExceptionTranslator
*/
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
JDBCException jdbcEx = (JDBCException) ex;
return this.jdbcExceptionTranslator.translate(
"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
}
return SessionFactoryUtils.convertHibernateAccessException(ex);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import java.sql.SQLException;
@@ -27,11 +27,9 @@ import org.springframework.dao.UncategorizedDataAccessException;
* for JDBC exceptions that Hibernate wrapped.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see SessionFactoryUtils#convertHibernateAccessException
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class HibernateJdbcException extends UncategorizedDataAccessException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
@@ -26,11 +26,9 @@ import org.springframework.orm.ObjectRetrievalFailureException;
* Converts Hibernate's UnresolvableObjectException and WrongClassException.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see SessionFactoryUtils#convertHibernateAccessException
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import java.io.Serializable;
import java.util.Collection;
@@ -38,33 +38,12 @@ import org.springframework.dao.DataAccessException;
* strongly encouraged to read the Hibernate {@code Session} javadocs
* for details on the semantics of those methods.
*
* <p>Note that operations that return an {@link java.util.Iterator} (i.e.
* {@code iterate(..)}) are supposed to be used within Spring-driven
* or JTA-driven transactions (with {@link HibernateTransactionManager},
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* or EJB CMT). Else, the {@code Iterator} won't be able to read
* results from its {@link java.sql.ResultSet} anymore, as the underlying
* Hibernate {@code Session} will already have been closed.
*
* <p>Note that lazy loading will just work with an open Hibernate
* {@code Session}, either within a transaction or within
* {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}/
* {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}.
* Furthermore, some operations just make sense within transactions,
* for example: {@code contains}, {@code evict}, {@code lock},
* {@code flush}, {@code clear}.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see HibernateTemplate
* @see org.hibernate.Session
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
public interface HibernateOperations {
/**
@@ -81,26 +60,12 @@ public interface HibernateOperations {
* disconnect, or reconnect, to let the template do its work.
* @param action callback object that specifies the Hibernate action
* @return a result object returned by the action, or {@code null}
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see HibernateTransactionManager
* @see org.hibernate.Session
*/
<T> T execute(HibernateCallback<T> action) throws DataAccessException;
/**
* Execute the specified action assuming that the result object is a
* {@link List}.
* <p>This is a convenience method for executing Hibernate find calls or
* queries within an action.
* @param action callback object that specifies the Hibernate action
* @return a List result returned by the action, or {@code null}
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @deprecated as of Spring 3.2.7, in favor of using a regular {@link #execute}
* call with a generic List type declared
*/
@Deprecated
List<?> executeFind(HibernateCallback<?> action) throws DataAccessException;
//-------------------------------------------------------------------------
// Convenience methods for loading individual objects
@@ -110,14 +75,14 @@ public interface HibernateOperations {
* Return the persistent instance of the given entity class
* with the given identifier, or {@code null} if not found.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#get(Class, java.io.Serializable)} for convenience.
* {@link org.hibernate.Session#get(Class, Serializable)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityClass a persistent class
* @param id the identifier of the persistent instance
* @return the persistent instance, or {@code null} if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable)
*/
<T> T get(Class<T> entityClass, Serializable id) throws DataAccessException;
@@ -126,15 +91,15 @@ public interface HibernateOperations {
* with the given identifier, or {@code null} if not found.
* <p>Obtains the specified lock mode if the instance exists.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#get(Class, java.io.Serializable, LockMode)} for convenience.
* {@link org.hibernate.Session#get(Class, Serializable, LockMode)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityClass a persistent class
* @param id the identifier of the persistent instance
* @param lockMode the lock mode to obtain
* @return the persistent instance, or {@code null} if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable, LockMode)
*/
<T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
@@ -142,14 +107,14 @@ public interface HibernateOperations {
* Return the persistent instance of the given entity class
* with the given identifier, or {@code null} if not found.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#get(String, java.io.Serializable)} for convenience.
* {@link org.hibernate.Session#get(String, Serializable)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityName the name of the persistent entity
* @param id the identifier of the persistent instance
* @return the persistent instance, or {@code null} if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable)
*/
Object get(String entityName, Serializable id) throws DataAccessException;
@@ -158,15 +123,15 @@ public interface HibernateOperations {
* with the given identifier, or {@code null} if not found.
* Obtains the specified lock mode if the instance exists.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#get(String, java.io.Serializable, LockMode)} for convenience.
* {@link org.hibernate.Session#get(String, Serializable, LockMode)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityName the name of the persistent entity
* @param id the identifier of the persistent instance
* @param lockMode the lock mode to obtain
* @return the persistent instance, or {@code null} if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable, LockMode)
*/
Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
@@ -174,15 +139,15 @@ public interface HibernateOperations {
* Return the persistent instance of the given entity class
* with the given identifier, throwing an exception if not found.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#load(Class, java.io.Serializable)} for convenience.
* {@link org.hibernate.Session#load(Class, Serializable)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityClass a persistent class
* @param id the identifier of the persistent instance
* @return the persistent instance
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, Serializable)
*/
<T> T load(Class<T> entityClass, Serializable id) throws DataAccessException;
@@ -191,7 +156,7 @@ public interface HibernateOperations {
* with the given identifier, throwing an exception if not found.
* Obtains the specified lock mode if the instance exists.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#load(Class, java.io.Serializable, LockMode)} for convenience.
* {@link org.hibernate.Session#load(Class, Serializable, LockMode)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityClass a persistent class
@@ -199,8 +164,8 @@ public interface HibernateOperations {
* @param lockMode the lock mode to obtain
* @return the persistent instance
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, Serializable)
*/
<T> T load(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
@@ -208,15 +173,15 @@ public interface HibernateOperations {
* Return the persistent instance of the given entity class
* with the given identifier, throwing an exception if not found.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#load(String, java.io.Serializable)} for convenience.
* {@link org.hibernate.Session#load(String, Serializable)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityName the name of the persistent entity
* @param id the identifier of the persistent instance
* @return the persistent instance
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, Serializable)
*/
Object load(String entityName, Serializable id) throws DataAccessException;
@@ -225,7 +190,7 @@ public interface HibernateOperations {
* with the given identifier, throwing an exception if not found.
* <p>Obtains the specified lock mode if the instance exists.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#load(String, java.io.Serializable, LockMode)} for convenience.
* {@link org.hibernate.Session#load(String, Serializable, LockMode)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entityName the name of the persistent entity
@@ -233,8 +198,8 @@ public interface HibernateOperations {
* @param lockMode the lock mode to obtain
* @return the persistent instance
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Class, Serializable)
*/
Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
@@ -243,7 +208,7 @@ public interface HibernateOperations {
* Note: Use queries or criteria for retrieving a specific subset.
* @param entityClass a persistent class
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
* @throws DataAccessException if there is a Hibernate error
* @see org.hibernate.Session#createCriteria
*/
<T> List<T> loadAll(Class<T> entityClass) throws DataAccessException;
@@ -252,21 +217,21 @@ public interface HibernateOperations {
* Load the persistent instance with the given identifier
* into the given object, throwing an exception if not found.
* <p>This method is a thin wrapper around
* {@link org.hibernate.Session#load(Object, java.io.Serializable)} for convenience.
* {@link org.hibernate.Session#load(Object, Serializable)} for convenience.
* For an explanation of the exact semantics of this method, please do refer to
* the Hibernate API documentation in the first instance.
* @param entity the object (of the target class) to load into
* @param id the identifier of the persistent instance
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Object, java.io.Serializable)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#load(Object, Serializable)
*/
void load(Object entity, Serializable id) throws DataAccessException;
/**
* Re-read the state of the given persistent instance.
* @param entity the persistent instance to re-read
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#refresh(Object)
*/
void refresh(Object entity) throws DataAccessException;
@@ -276,8 +241,8 @@ public interface HibernateOperations {
* Obtains the specified lock mode for the instance.
* @param entity the persistent instance to re-read
* @param lockMode the lock mode to obtain
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#refresh(Object, org.hibernate.LockMode)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#refresh(Object, LockMode)
*/
void refresh(Object entity, LockMode lockMode) throws DataAccessException;
@@ -285,7 +250,7 @@ public interface HibernateOperations {
* Check whether the given object is in the Session cache.
* @param entity the persistence instance to check
* @return whether the given object is in the Session cache
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
* @throws DataAccessException if there is a Hibernate error
* @see org.hibernate.Session#contains
*/
boolean contains(Object entity) throws DataAccessException;
@@ -293,7 +258,7 @@ public interface HibernateOperations {
/**
* Remove the given object from the {@link org.hibernate.Session} cache.
* @param entity the persistent instance to evict
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#evict
*/
void evict(Object entity) throws DataAccessException;
@@ -329,8 +294,8 @@ public interface HibernateOperations {
* @param entity the persistent instance to lock
* @param lockMode the lock mode to obtain
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#lock(Object, org.hibernate.LockMode)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#lock(Object, LockMode)
*/
void lock(Object entity, LockMode lockMode) throws DataAccessException;
@@ -341,8 +306,8 @@ public interface HibernateOperations {
* @param entity the persistent instance to lock
* @param lockMode the lock mode to obtain
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#lock(String, Object, org.hibernate.LockMode)
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#lock(String, Object, LockMode)
*/
void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
@@ -350,7 +315,7 @@ public interface HibernateOperations {
* Persist the given transient instance.
* @param entity the transient instance to persist
* @return the generated identifier
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#save(Object)
*/
Serializable save(Object entity) throws DataAccessException;
@@ -360,7 +325,7 @@ public interface HibernateOperations {
* @param entityName the name of the persistent entity
* @param entity the transient instance to persist
* @return the generated identifier
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#save(String, Object)
*/
Serializable save(String entityName, Object entity) throws DataAccessException;
@@ -369,7 +334,7 @@ public interface HibernateOperations {
* Update the given persistent instance,
* associating it with the current Hibernate {@link org.hibernate.Session}.
* @param entity the persistent instance to update
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#update(Object)
*/
void update(Object entity) throws DataAccessException;
@@ -382,7 +347,7 @@ public interface HibernateOperations {
* @param entity the persistent instance to update
* @param lockMode the lock mode to obtain
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#update(Object)
*/
void update(Object entity, LockMode lockMode) throws DataAccessException;
@@ -392,7 +357,7 @@ public interface HibernateOperations {
* associating it with the current Hibernate {@link org.hibernate.Session}.
* @param entityName the name of the persistent entity
* @param entity the persistent instance to update
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#update(String, Object)
*/
void update(String entityName, Object entity) throws DataAccessException;
@@ -406,7 +371,7 @@ public interface HibernateOperations {
* @param entity the persistent instance to update
* @param lockMode the lock mode to obtain
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#update(String, Object)
*/
void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
@@ -440,7 +405,7 @@ public interface HibernateOperations {
* @param entity the persistent object to replicate
* @param replicationMode the Hibernate ReplicationMode
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
* @see org.hibernate.Session#replicate(Object, ReplicationMode)
*/
void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException;
@@ -451,7 +416,7 @@ public interface HibernateOperations {
* @param entity the persistent object to replicate
* @param replicationMode the Hibernate ReplicationMode
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#replicate(String, Object, org.hibernate.ReplicationMode)
* @see org.hibernate.Session#replicate(String, Object, ReplicationMode)
*/
void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException;
@@ -460,7 +425,7 @@ public interface HibernateOperations {
* <p>Similar to {@code save}, associating the given object
* with the current Hibernate {@link org.hibernate.Session}.
* @param entity the persistent instance to persist
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#persist(Object)
* @see #save
*/
@@ -472,7 +437,7 @@ public interface HibernateOperations {
* with the current Hibernate {@link org.hibernate.Session}.
* @param entityName the name of the persistent entity
* @param entity the persistent instance to persist
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#persist(String, Object)
* @see #save
*/
@@ -491,10 +456,9 @@ public interface HibernateOperations {
* object graph too.
* @param entity the object to merge with the corresponding persistence instance
* @return the updated, registered persistent instance
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#merge(Object)
* @see #saveOrUpdate
* @see org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener
*/
<T> T merge(T entity) throws DataAccessException;
@@ -512,7 +476,7 @@ public interface HibernateOperations {
* @param entityName the name of the persistent entity
* @param entity the object to merge with the corresponding persistence instance
* @return the updated, registered persistent instance
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#merge(String, Object)
* @see #saveOrUpdate
*/
@@ -521,7 +485,7 @@ public interface HibernateOperations {
/**
* Delete the given persistent instance.
* @param entity the persistent instance to delete
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#delete(Object)
*/
void delete(Object entity) throws DataAccessException;
@@ -533,7 +497,7 @@ public interface HibernateOperations {
* @param entity the persistent instance to delete
* @param lockMode the lock mode to obtain
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#delete(Object)
*/
void delete(Object entity, LockMode lockMode) throws DataAccessException;
@@ -542,7 +506,7 @@ public interface HibernateOperations {
* Delete the given persistent instance.
* @param entityName the name of the persistent entity
* @param entity the persistent instance to delete
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#delete(Object)
*/
void delete(String entityName, Object entity) throws DataAccessException;
@@ -555,7 +519,7 @@ public interface HibernateOperations {
* @param entity the persistent instance to delete
* @param lockMode the lock mode to obtain
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#delete(Object)
*/
void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
@@ -565,7 +529,7 @@ public interface HibernateOperations {
* <p>This can be combined with any of the find methods to delete by query
* in two lines of code.
* @param entities the persistent instances to delete
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#delete(Object)
*/
void deleteAll(Collection<?> entities) throws DataAccessException;
@@ -576,7 +540,7 @@ public interface HibernateOperations {
* JDBC code needs to see certain changes within the same transaction.
* Else, it is preferable to rely on auto-flushing at transaction
* completion.
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#flush
*/
void flush() throws DataAccessException;
@@ -584,7 +548,7 @@ public interface HibernateOperations {
/**
* Remove all objects from the {@link org.hibernate.Session} cache, and
* cancel all pending saves, updates and deletes.
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#clear
*/
void clear() throws DataAccessException;
@@ -594,33 +558,13 @@ public interface HibernateOperations {
// Convenience finder methods for HQL strings
//-------------------------------------------------------------------------
/**
* Execute an HQL query.
* @param queryString a query expressed in Hibernate's query language
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
*/
List<?> find(String queryString) throws DataAccessException;
/**
* Execute an HQL query, binding one value to a "?" parameter in the
* query string.
* @param queryString a query expressed in Hibernate's query language
* @param value the value of the parameter
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
*/
List<?> find(String queryString, Object value) throws DataAccessException;
/**
* Execute an HQL query, binding a number of values to "?" parameters
* in the query string.
* @param queryString a query expressed in Hibernate's query language
* @param values the values of the parameters
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
*/
List<?> find(String queryString, Object... values) throws DataAccessException;
@@ -632,7 +576,7 @@ public interface HibernateOperations {
* @param paramName the name of the parameter
* @param value the value of the parameter
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedParam(String queryString, String paramName, Object value) throws DataAccessException;
@@ -644,7 +588,7 @@ public interface HibernateOperations {
* @param paramNames the names of the parameters
* @param values the values of the parameters
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedParam(String queryString, String[] paramNames, Object[] values) throws DataAccessException;
@@ -655,7 +599,7 @@ public interface HibernateOperations {
* @param queryString a query expressed in Hibernate's query language
* @param valueBean the values of the parameters
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Query#setProperties
* @see org.hibernate.Session#createQuery
*/
@@ -666,28 +610,6 @@ public interface HibernateOperations {
// Convenience finder methods for named queries
//-------------------------------------------------------------------------
/**
* Execute a named query.
* <p>A named query is defined in a Hibernate mapping file.
* @param queryName the name of a Hibernate query in a mapping file
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedQuery(String queryName) throws DataAccessException;
/**
* Execute a named query, binding one value to a "?" parameter in
* the query string.
* <p>A named query is defined in a Hibernate mapping file.
* @param queryName the name of a Hibernate query in a mapping file
* @param value the value of the parameter
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedQuery(String queryName, Object value) throws DataAccessException;
/**
* Execute a named query binding a number of values to "?" parameters
* in the query string.
@@ -695,7 +617,7 @@ public interface HibernateOperations {
* @param queryName the name of a Hibernate query in a mapping file
* @param values the values of the parameters
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedQuery(String queryName, Object... values) throws DataAccessException;
@@ -708,7 +630,7 @@ public interface HibernateOperations {
* @param paramName the name of parameter
* @param value the value of the parameter
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
@@ -722,7 +644,7 @@ public interface HibernateOperations {
* @param paramNames the names of the parameters
* @param values the values of the parameters
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#getNamedQuery(String)
*/
List<?> findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values)
@@ -735,7 +657,7 @@ public interface HibernateOperations {
* @param queryName the name of a Hibernate query in a mapping file
* @param valueBean the values of the parameters
* @return a {@link List} containing the results of the query execution
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Query#setProperties
* @see org.hibernate.Session#getNamedQuery(String)
*/
@@ -752,8 +674,8 @@ public interface HibernateOperations {
* <b>Note: Do not reuse criteria objects! They need to recreated per execution,
* due to the suboptimal design of Hibernate's criteria facility.</b>
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
* @throws DataAccessException in case of Hibernate errors
* @see DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
*/
List<?> findByCriteria(DetachedCriteria criteria) throws DataAccessException;
@@ -767,8 +689,8 @@ public interface HibernateOperations {
* @param maxResults the maximum number of result objects to retrieve
* (or <=0 for no limit)
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
* @throws DataAccessException in case of Hibernate errors
* @see DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
* @see org.hibernate.Criteria#setFirstResult(int)
* @see org.hibernate.Criteria#setMaxResults(int)
*/
@@ -779,7 +701,7 @@ public interface HibernateOperations {
* @param exampleEntity an instance of the desired entity,
* serving as example for "query-by-example"
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.criterion.Example#create(Object)
*/
<T> List<T> findByExample(T exampleEntity) throws DataAccessException;
@@ -790,7 +712,7 @@ public interface HibernateOperations {
* @param exampleEntity an instance of the desired entity,
* serving as example for "query-by-example"
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.criterion.Example#create(Object)
*/
<T> List<T> findByExample(String entityName, T exampleEntity) throws DataAccessException;
@@ -804,7 +726,7 @@ public interface HibernateOperations {
* @param maxResults the maximum number of result objects to retrieve
* (or <=0 for no limit)
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.criterion.Example#create(Object)
* @see org.hibernate.Criteria#setFirstResult(int)
* @see org.hibernate.Criteria#setMaxResults(int)
@@ -821,7 +743,7 @@ public interface HibernateOperations {
* @param maxResults the maximum number of result objects to retrieve
* (or <=0 for no limit)
* @return a {@link List} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.criterion.Example#create(Object)
* @see org.hibernate.Criteria#setFirstResult(int)
* @see org.hibernate.Criteria#setMaxResults(int)
@@ -834,32 +756,6 @@ public interface HibernateOperations {
// Convenience query methods for iteration and bulk updates/deletes
//-------------------------------------------------------------------------
/**
* Execute a query for persistent instances.
* <p>Returns the results as an {@link Iterator}. Entities returned are
* initialized on demand. See the Hibernate API documentation for details.
* @param queryString a query expressed in Hibernate's query language
* @return an {@link Iterator} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
* @see org.hibernate.Query#iterate
*/
Iterator<?> iterate(String queryString) throws DataAccessException;
/**
* Execute a query for persistent instances, binding one value
* to a "?" parameter in the query string.
* <p>Returns the results as an {@link Iterator}. Entities returned are
* initialized on demand. See the Hibernate API documentation for details.
* @param queryString a query expressed in Hibernate's query language
* @param value the value of the parameter
* @return an {@link Iterator} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
* @see org.hibernate.Query#iterate
*/
Iterator<?> iterate(String queryString, Object value) throws DataAccessException;
/**
* Execute a query for persistent instances, binding a number of
* values to "?" parameters in the query string.
@@ -868,7 +764,7 @@ public interface HibernateOperations {
* @param queryString a query expressed in Hibernate's query language
* @param values the values of the parameters
* @return an {@link Iterator} containing 0 or more persistent instances
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
* @see org.hibernate.Query#iterate
*/
@@ -884,35 +780,13 @@ public interface HibernateOperations {
*/
void closeIterator(Iterator<?> it) throws DataAccessException;
/**
* Update/delete all objects according to the given query.
* @param queryString an update/delete query expressed in Hibernate's query language
* @return the number of instances updated/deleted
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
* @see org.hibernate.Query#executeUpdate
*/
int bulkUpdate(String queryString) throws DataAccessException;
/**
* Update/delete all objects according to the given query, binding one value
* to a "?" parameter in the query string.
* @param queryString an update/delete query expressed in Hibernate's query language
* @param value the value of the parameter
* @return the number of instances updated/deleted
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
* @see org.hibernate.Query#executeUpdate
*/
int bulkUpdate(String queryString, Object value) throws DataAccessException;
/**
* Update/delete all objects according to the given query, binding a number of
* values to "?" parameters in the query string.
* @param queryString an update/delete query expressed in Hibernate's query language
* @param values the values of the parameters
* @return the number of instances updated/deleted
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#createQuery
* @see org.hibernate.Query#executeUpdate
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,25 +14,23 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import org.hibernate.OptimisticLockException;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
/**
* Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
* Converts Hibernate's StaleObjectStateException, StaleStateException
* and OptimisticLockException.
* and OptimisticEntityLockException.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see SessionFactoryUtils#convertHibernateAccessException
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
@@ -44,7 +42,7 @@ public class HibernateOptimisticLockingFailureException extends ObjectOptimistic
super(ex.getMessage(), ex);
}
public HibernateOptimisticLockingFailureException(OptimisticLockException ex) {
public HibernateOptimisticLockingFailureException(OptimisticEntityLockException ex) {
super(ex.getMessage(), ex);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import org.hibernate.QueryException;
@@ -25,11 +25,9 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
* thrown on invalid HQL query syntax.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see SessionFactoryUtils#convertHibernateAccessException
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class HibernateQueryException extends InvalidDataAccessResourceUsageException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
@@ -26,11 +26,9 @@ import org.springframework.dao.UncategorizedDataAccessException;
* {@code org.springframework.dao} exceptions.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see SessionFactoryUtils#convertHibernateAccessException
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class HibernateSystemException extends UncategorizedDataAccessException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,36 +14,36 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.LockOptions;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.event.EventSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
@@ -64,54 +64,30 @@ import org.springframework.util.Assert;
* always be configured as bean in the application context, in the first case
* given to the service directly, in the second case to the prepared template.
*
* <p><b>NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
* also be coded in plain Hibernate style. Hence, for newly started projects,
* consider adopting the standard Hibernate3 style of coding data access objects
* instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.</b>
*
* <p>This class can be considered as direct alternative to working with the raw
* Hibernate3 Session API (through {@code SessionFactory.getCurrentSession()}).
* The major advantage is its automatic conversion to DataAccessExceptions as well
* as its capability to fall back to 'auto-commit' style behavior when used outside
* of transactions. <b>Note that HibernateTemplate will perform its own Session
* management, not participating in a custom Hibernate CurrentSessionContext
* unless you explicitly switch {@link #setAllowCreate "allowCreate"} to "false".</b>
*
* <p>{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference
* to a specific Hibernate SessionFactory, at least in a non-EJB environment.
* The Spring application context will manage its lifecycle, initializing and
* shutting down the factory as part of the application.
*
* <p>Note that operations that return an Iterator (i.e. {@code iterate})
* are supposed to be used within Spring-driven or JTA-driven transactions
* (with HibernateTransactionManager, JtaTransactionManager, or EJB CMT).
* Else, the Iterator won't be able to read results from its ResultSet anymore,
* as the underlying Hibernate Session will already have been closed.
*
* <p>Lazy loading will also just work with an open Hibernate Session,
* either within a transaction or within OpenSessionInViewFilter/Interceptor.
* Furthermore, some operations just make sense within transactions,
* for example: {@code contains}, {@code evict}, {@code lock},
* {@code flush}, {@code clear}.
* <p><b>NOTE: Hibernate access code can also be coded in plain Hibernate style.
* Hence, for newly started projects, consider adopting the standard Hibernate
* style of coding data access objects instead, based on
* {@link SessionFactory#getCurrentSession()}.
* This HibernateTemplate primarily exists as a migration helper for Hibernate 3
* based data access code, to benefit from bug fixes in Hibernate 5.x.</b>
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see #setSessionFactory
* @see HibernateCallback
* @see org.hibernate.Session
* @see Session
* @see LocalSessionFactoryBean
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
* @see org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
* @see org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor
*/
@Deprecated
public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
public class HibernateTemplate implements HibernateOperations, InitializingBean {
private boolean allowCreate = true;
protected final Log logger = LogFactory.getLog(getClass());
private boolean alwaysUseNewSession = false;
private SessionFactory sessionFactory;
private String[] filterNames;
private boolean exposeNativeSession = false;
@@ -141,72 +117,42 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
afterPropertiesSet();
}
/**
* Create a new HibernateTemplate instance.
* @param sessionFactory the SessionFactory to create Sessions with
* @param allowCreate if a non-transactional Session should be created when no
* transactional Session can be found for the current thread
*/
public HibernateTemplate(SessionFactory sessionFactory, boolean allowCreate) {
setSessionFactory(sessionFactory);
setAllowCreate(allowCreate);
afterPropertiesSet();
}
/**
* Set if a new {@link Session} should be created when no transactional
* {@code Session} can be found for the current thread.
* The default value is {@code true}.
* <p>{@code HibernateTemplate} is aware of a corresponding
* {@code Session} bound to the current thread, for example when using
* {@link HibernateTransactionManager}. If {@code allowCreate} is
* {@code true}, a new non-transactional {@code Session} will be
* created if none is found, which needs to be closed at the end of the operation.
* If {@code false}, an {@link IllegalStateException} will get thrown in
* this case.
* <p><b>NOTE: As of Spring 2.5, switching {@code allowCreate}
* to {@code false} will delegate to Hibernate's
* {@link org.hibernate.SessionFactory#getCurrentSession()} method,</b>
* which - with Spring-based setup - will by default delegate to Spring's
* {@code SessionFactoryUtils.getSession(sessionFactory, false)}.
* This mode also allows for custom Hibernate CurrentSessionContext strategies
* to be plugged in, whereas {@code allowCreate} set to {@code true}
* will always use a Spring-managed Hibernate Session.
* @see SessionFactoryUtils#getSession(SessionFactory, boolean)
* Set the Hibernate SessionFactory that should be used to create
* Hibernate Sessions.
*/
public void setAllowCreate(boolean allowCreate) {
this.allowCreate = allowCreate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Return if a new Session should be created if no thread-bound found.
* Return the Hibernate SessionFactory that should be used to create
* Hibernate Sessions.
*/
public boolean isAllowCreate() {
return this.allowCreate;
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
/**
* Set whether to always use a new Hibernate Session for this template.
* Default is "false"; if activated, all operations on this template will
* work on a new Hibernate Session even in case of a pre-bound Session
* (for example, within a transaction or OpenSessionInViewFilter).
* <p>Within a transaction, a new Hibernate Session used by this template
* will participate in the transaction through using the same JDBC
* Connection. In such a scenario, multiple Sessions will participate
* in the same database transaction.
* <p>Turn this on for operations that are supposed to always execute
* independently, without side effects caused by a shared Hibernate Session.
* Set one or more names of Hibernate filters to be activated for all
* Sessions that this accessor works with.
* <p>Each of those filters will be enabled at the beginning of each
* operation and correspondingly disabled at the end of the operation.
* This will work for newly opened Sessions as well as for existing
* Sessions (for example, within a transaction).
* @see #enableFilters(Session)
* @see Session#enableFilter(String)
*/
public void setAlwaysUseNewSession(boolean alwaysUseNewSession) {
this.alwaysUseNewSession = alwaysUseNewSession;
public void setFilterNames(String... filterNames) {
this.filterNames = filterNames;
}
/**
* Return whether to always use a new Hibernate Session for this template.
* Return the names of Hibernate filters to be activated, if any.
*/
public boolean isAlwaysUseNewSession() {
return this.alwaysUseNewSession;
public String[] getFilterNames() {
return this.filterNames;
}
/**
@@ -216,7 +162,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* {@code close} calls and automatically applying query cache
* settings and transaction timeouts.
* @see HibernateCallback
* @see org.hibernate.Session
* @see Session
* @see #setCacheQueries
* @see #setQueryCacheRegion
* @see #prepareQuery
@@ -239,8 +185,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* in case of write operations (save/update/delete).
* <p>Default is "true", for fail-fast behavior when attempting write operations
* within a read-only transaction. Turn this off to allow save/update/delete
* on a Session with flush mode NEVER.
* @see #setFlushMode
* on a Session with flush mode MANUAL.
* @see #checkWriteOperationAllowed
* @see org.springframework.transaction.TransactionDefinition#isReadOnly
*/
@@ -265,7 +210,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* by this template, set the "queryCacheRegion" property.
* @see #setQueryCacheRegion
* @see org.hibernate.Query#setCacheable
* @see org.hibernate.Criteria#setCacheable
* @see Criteria#setCacheable
*/
public void setCacheQueries(boolean cacheQueries) {
this.cacheQueries = cacheQueries;
@@ -286,7 +231,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* template are configured to be cached via the "cacheQueries" property.
* @see #setCacheQueries
* @see org.hibernate.Query#setCacheRegion
* @see org.hibernate.Criteria#setCacheRegion
* @see Criteria#setCacheRegion
*/
public void setQueryCacheRegion(String queryCacheRegion) {
this.queryCacheRegion = queryCacheRegion;
@@ -336,141 +281,77 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
return this.maxResults;
}
@Override
public void afterPropertiesSet() {
if (getSessionFactory() == null) {
throw new IllegalArgumentException("Property 'sessionFactory' is required");
}
}
@Override
public <T> T execute(HibernateCallback<T> action) throws DataAccessException {
return doExecute(action, false, false);
}
@Override
@Deprecated
public List<?> executeFind(HibernateCallback<?> action) throws DataAccessException {
Object result = doExecute(action, false, false);
if (result != null && !(result instanceof List)) {
throw new InvalidDataAccessApiUsageException(
"Result object returned from HibernateCallback isn't a List: [" + result + "]");
}
return (List<?>) result;
return doExecute(action, false);
}
/**
* Execute the action specified by the given action object within a
* new {@link org.hibernate.Session}.
* <p>This execute variant overrides the template-wide
* {@link #isAlwaysUseNewSession() "alwaysUseNewSession"} setting.
* @param action callback object that specifies the Hibernate action
* @return a result object returned by the action, or {@code null}
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
*/
public <T> T executeWithNewSession(HibernateCallback<T> action) {
return doExecute(action, true, false);
}
/**
* Execute the action specified by the given action object within a
* native {@link org.hibernate.Session}.
* native {@link Session}.
* <p>This execute variant overrides the template-wide
* {@link #isExposeNativeSession() "exposeNativeSession"} setting.
* @param action callback object that specifies the Hibernate action
* @return a result object returned by the action, or {@code null}
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
*/
public <T> T executeWithNativeSession(HibernateCallback<T> action) {
return doExecute(action, false, true);
return doExecute(action, true);
}
/**
* Execute the action specified by the given action object within a Session.
* @param action callback object that specifies the Hibernate action
* @param enforceNewSession whether to enforce a new Session for this template
* even if there is a pre-bound transactional Session
* @param enforceNativeSession whether to enforce exposure of the native
* Hibernate Session to callback code
* @return a result object returned by the action, or {@code null}
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
* @throws DataAccessException in case of Hibernate errors
*/
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNewSession, boolean enforceNativeSession)
throws DataAccessException {
@SuppressWarnings("deprecation")
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Session session = (enforceNewSession ?
SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
boolean existingTransaction = (!enforceNewSession &&
(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateTemplate");
Session session = null;
boolean isNew = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (HibernateException ex) {
logger.debug("Could not retrieve pre-bound Hibernate session", ex);
}
if (session == null) {
session = getSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
isNew = true;
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(session);
Session sessionToExpose =
(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
T result = action.doInHibernate(sessionToExpose);
flushIfNecessary(session, existingTransaction);
return result;
return action.doInHibernate(sessionToExpose);
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (SQLException ex) {
throw convertJdbcAccessException(ex);
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
catch (RuntimeException ex) {
// Callback code threw application exception...
throw ex;
}
finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
disableFilters(session);
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
if (isNew) {
SessionFactoryUtils.closeSession(session);
}
else {
// Never use deferred close for an explicitly new Session.
if (isAlwaysUseNewSession()) {
SessionFactoryUtils.closeSession(session);
}
else {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
}
}
}
}
/**
* Return a Session for use by this template.
* <p>Returns a new Session in case of "alwaysUseNewSession" (using the same
* JDBC Connection as a transactional Session, if applicable), a pre-bound
* Session in case of "allowCreate" turned off, and a pre-bound or new Session
* otherwise (new only if no transactional or otherwise pre-bound Session exists).
* @return the Session to use (never {@code null})
* @see SessionFactoryUtils#getSession
* @see SessionFactoryUtils#getNewSession
* @see #setAlwaysUseNewSession
* @see #setAllowCreate
*/
protected Session getSession() {
if (isAlwaysUseNewSession()) {
return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());
}
else if (isAllowCreate()) {
return SessionFactoryUtils.getSession(
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
}
else if (SessionFactoryUtils.hasTransactionalSession(getSessionFactory())) {
return SessionFactoryUtils.getSession(getSessionFactory(), false);
}
else {
try {
return getSessionFactory().getCurrentSession();
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not obtain current Hibernate Session", ex);
disableFilters(session);
}
}
}
@@ -480,28 +361,46 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* The proxy also prepares returned Query and Criteria objects.
* @param session the Hibernate Session to create a proxy for
* @return the Session proxy
* @see org.hibernate.Session#close()
* @see Session#close()
* @see #prepareQuery
* @see #prepareCriteria
*/
protected Session createSessionProxy(Session session) {
Class<?>[] sessionIfcs;
Class<?> mainIfc = (session instanceof org.hibernate.classic.Session ?
org.hibernate.classic.Session.class : Session.class);
if (session instanceof EventSource) {
sessionIfcs = new Class<?>[] {mainIfc, EventSource.class};
}
else if (session instanceof SessionImplementor) {
sessionIfcs = new Class<?>[] {mainIfc, SessionImplementor.class};
}
else {
sessionIfcs = new Class<?>[] {mainIfc};
}
return (Session) Proxy.newProxyInstance(
session.getClass().getClassLoader(), sessionIfcs,
session.getClass().getClassLoader(), new Class<?>[] {Session.class},
new CloseSuppressingInvocationHandler(session));
}
/**
* Enable the specified filters on the given Session.
* @param session the current Hibernate Session
* @see #setFilterNames
* @see Session#enableFilter(String)
*/
protected void enableFilters(Session session) {
String[] filterNames = getFilterNames();
if (filterNames != null) {
for (String filterName : filterNames) {
session.enableFilter(filterName);
}
}
}
/**
* Disable the specified filters on the given Session.
* @param session the current Hibernate Session
* @see #setFilterNames
* @see Session#disableFilter(String)
*/
protected void disableFilters(Session session) {
String[] filterNames = getFilterNames();
if (filterNames != null) {
for (String filterName : filterNames) {
session.disableFilter(filterName);
}
}
}
//-------------------------------------------------------------------------
// Convenience methods for loading individual objects
@@ -518,13 +417,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
return executeWithNativeSession(new HibernateCallback<T>() {
@Override
@SuppressWarnings("unchecked")
public T doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return (T) session.get(entityClass, id, lockMode);
return session.get(entityClass, id, new LockOptions(lockMode));
}
else {
return (T) session.get(entityClass, id);
return session.get(entityClass, id);
}
}
});
@@ -543,7 +441,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
@Override
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.get(entityName, id, lockMode);
return session.get(entityName, id, new LockOptions(lockMode));
}
else {
return session.get(entityName, id);
@@ -563,13 +461,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
return executeWithNativeSession(new HibernateCallback<T>() {
@Override
@SuppressWarnings("unchecked")
public T doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return (T) session.load(entityClass, id, lockMode);
return session.load(entityClass, id, new LockOptions(lockMode));
}
else {
return (T) session.load(entityClass, id);
return session.load(entityClass, id);
}
}
});
@@ -588,7 +485,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
@Override
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.load(entityName, id, lockMode);
return session.load(entityName, id, new LockOptions(lockMode));
}
else {
return session.load(entityName, id);
@@ -601,7 +498,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
public <T> List<T> loadAll(final Class<T> entityClass) throws DataAccessException {
return executeWithNativeSession(new HibernateCallback<List<T>>() {
@Override
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "deprecation"})
public List<T> doInHibernate(Session session) throws HibernateException {
Criteria criteria = session.createCriteria(entityClass);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
@@ -633,7 +530,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
@Override
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
session.refresh(entity, lockMode);
session.refresh(entity, new LockOptions(lockMode));
}
else {
session.refresh(entity);
@@ -676,7 +573,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
@Override
public Filter enableFilter(String filterName) throws IllegalStateException {
Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
Session session = getSessionFactory().getCurrentSession();
Filter filter = session.getEnabledFilter(filterName);
if (filter == null) {
filter = session.enableFilter(filterName);
@@ -694,7 +591,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
executeWithNativeSession(new HibernateCallback<Object>() {
@Override
public Object doInHibernate(Session session) throws HibernateException {
session.lock(entity, lockMode);
session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
return null;
}
});
@@ -707,7 +604,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
executeWithNativeSession(new HibernateCallback<Object>() {
@Override
public Object doInHibernate(Session session) throws HibernateException {
session.lock(entityName, entity, lockMode);
session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity);
return null;
}
});
@@ -748,7 +645,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
checkWriteOperationAllowed(session);
session.update(entity);
if (lockMode != null) {
session.lock(entity, lockMode);
session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
}
return null;
}
@@ -770,7 +667,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
checkWriteOperationAllowed(session);
session.update(entityName, entity);
if (lockMode != null) {
session.lock(entity, lockMode);
session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity);
}
return null;
}
@@ -889,7 +786,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
if (lockMode != null) {
session.lock(entity, lockMode);
session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
}
session.delete(entity);
return null;
@@ -911,7 +808,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
if (lockMode != null) {
session.lock(entityName, entity, lockMode);
session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity);
}
session.delete(entityName, entity);
return null;
@@ -960,22 +857,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
// Convenience finder methods for HQL strings
//-------------------------------------------------------------------------
@Override
public List<?> find(String queryString) throws DataAccessException {
return find(queryString, (Object[]) null);
}
@Override
public List<?> find(String queryString, Object value) throws DataAccessException {
return find(queryString, new Object[] {value});
}
@Override
public List<?> find(final String queryString, final Object... values) throws DataAccessException {
return executeWithNativeSession(new HibernateCallback<List<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public List<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
org.hibernate.Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
@@ -1003,13 +891,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
}
return executeWithNativeSession(new HibernateCallback<List<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public List<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
org.hibernate.Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
}
for (int i = 0; i < values.length; i++) {
applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
}
return queryObject.list();
}
@@ -1022,8 +909,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
return executeWithNativeSession(new HibernateCallback<List<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public List<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
org.hibernate.Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
queryObject.setProperties(valueBean);
return queryObject.list();
@@ -1036,22 +924,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
// Convenience finder methods for named queries
//-------------------------------------------------------------------------
@Override
public List<?> findByNamedQuery(String queryName) throws DataAccessException {
return findByNamedQuery(queryName, (Object[]) null);
}
@Override
public List<?> findByNamedQuery(String queryName, Object value) throws DataAccessException {
return findByNamedQuery(queryName, new Object[] {value});
}
@Override
public List<?> findByNamedQuery(final String queryName, final Object... values) throws DataAccessException {
return executeWithNativeSession(new HibernateCallback<List<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public List<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.getNamedQuery(queryName);
org.hibernate.Query queryObject = session.getNamedQuery(queryName);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
@@ -1080,8 +959,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
}
return executeWithNativeSession(new HibernateCallback<List<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public List<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.getNamedQuery(queryName);
org.hibernate.Query queryObject = session.getNamedQuery(queryName);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
@@ -1099,8 +979,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
return executeWithNativeSession(new HibernateCallback<List<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public List<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.getNamedQuery(queryName);
org.hibernate.Query queryObject = session.getNamedQuery(queryName);
prepareQuery(queryObject);
queryObject.setProperties(valueBean);
return queryObject.list();
@@ -1155,6 +1036,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
}
@Override
@SuppressWarnings("deprecation")
public <T> List<T> findByExample(
final String entityName, final T exampleEntity, final int firstResult, final int maxResults)
throws DataAccessException {
@@ -1184,22 +1066,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
// Convenience query methods for iteration and bulk updates/deletes
//-------------------------------------------------------------------------
@Override
public Iterator<?> iterate(String queryString) throws DataAccessException {
return iterate(queryString, (Object[]) null);
}
@Override
public Iterator<?> iterate(String queryString, Object value) throws DataAccessException {
return iterate(queryString, new Object[] {value});
}
@Override
public Iterator<?> iterate(final String queryString, final Object... values) throws DataAccessException {
return executeWithNativeSession(new HibernateCallback<Iterator<?>>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public Iterator<?> doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
org.hibernate.Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
@@ -1221,22 +1094,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
}
}
@Override
public int bulkUpdate(String queryString) throws DataAccessException {
return bulkUpdate(queryString, (Object[]) null);
}
@Override
public int bulkUpdate(String queryString, Object value) throws DataAccessException {
return bulkUpdate(queryString, new Object[] {value});
}
@Override
public int bulkUpdate(final String queryString, final Object... values) throws DataAccessException {
return executeWithNativeSession(new HibernateCallback<Integer>() {
@Override
@SuppressWarnings({"rawtypes", "deprecation"})
public Integer doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
org.hibernate.Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
@@ -1260,14 +1124,11 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* @param session current Hibernate Session
* @throws InvalidDataAccessApiUsageException if write operations are not allowed
* @see #setCheckWriteOperations
* @see #getFlushMode()
* @see #FLUSH_EAGER
* @see org.hibernate.Session#getFlushMode()
* @see org.hibernate.FlushMode#MANUAL
* @see Session#getFlushMode()
* @see FlushMode#MANUAL
*/
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
session.getFlushMode().lessThan(FlushMode.COMMIT)) {
if (isCheckWriteOperations() && SessionFactoryUtils.getFlushMode(session).lessThan(FlushMode.COMMIT)) {
throw new InvalidDataAccessApiUsageException(
"Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+
"Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
@@ -1280,9 +1141,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* @param queryObject the Query object to prepare
* @see #setCacheQueries
* @see #setQueryCacheRegion
* @see SessionFactoryUtils#applyTransactionTimeout
*/
protected void prepareQuery(Query queryObject) {
@SuppressWarnings({"rawtypes", "deprecation"})
protected void prepareQuery(org.hibernate.Query queryObject) {
if (isCacheQueries()) {
queryObject.setCacheable(true);
if (getQueryCacheRegion() != null) {
@@ -1295,7 +1156,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
if (getMaxResults() > 0) {
queryObject.setMaxResults(getMaxResults());
}
SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null && sessionHolder.hasTimeout()) {
queryObject.setTimeout(sessionHolder.getTimeToLiveInSeconds());
}
}
/**
@@ -1304,7 +1170,6 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* @param criteria the Criteria object to prepare
* @see #setCacheQueries
* @see #setQueryCacheRegion
* @see SessionFactoryUtils#applyTransactionTimeout
*/
protected void prepareCriteria(Criteria criteria) {
if (isCacheQueries()) {
@@ -1319,7 +1184,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
if (getMaxResults() > 0) {
criteria.setMaxResults(getMaxResults());
}
SessionFactoryUtils.applyTransactionTimeout(criteria, getSessionFactory());
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null && sessionHolder.hasTimeout()) {
criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
}
}
/**
@@ -1329,7 +1199,8 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
* @param value the value of the parameter
* @throws HibernateException if thrown by the Query object
*/
protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value)
@SuppressWarnings({"rawtypes", "deprecation"})
protected void applyNamedParameterToQuery(org.hibernate.Query queryObject, String paramName, Object value)
throws HibernateException {
if (value instanceof Collection) {
@@ -1347,7 +1218,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
/**
* Invocation handler that suppresses close calls on Hibernate Sessions.
* Also prepares returned Query and Criteria objects.
* @see org.hibernate.Session#close
* @see Session#close
*/
private class CloseSuppressingInvocationHandler implements InvocationHandler {
@@ -1358,6 +1229,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
}
@Override
@SuppressWarnings("deprecation")
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Invocation on Session interface coming in...
@@ -1380,8 +1252,8 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
// If return value is a Query or Criteria, apply transaction timeout.
// Applies to createQuery, getNamedQuery, createCriteria.
if (retVal instanceof Query) {
prepareQuery(((Query) retVal));
if (retVal instanceof org.hibernate.Query) {
prepareQuery(((org.hibernate.Query) retVal));
}
if (retVal instanceof Criteria) {
prepareCriteria(((Criteria) retVal));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,21 +14,21 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3;
package org.springframework.orm.hibernate5;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.sql.DataSource;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.exception.GenericJDBCException;
import org.hibernate.impl.SessionImpl;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
@@ -40,8 +40,6 @@ import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidIsolationLevelException;
@@ -54,13 +52,12 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
/**
* {@link org.springframework.transaction.PlatformTransactionManager}
* implementation for a single Hibernate {@link org.hibernate.SessionFactory}.
* Binds a Hibernate Session from the specified factory to the thread, potentially
* allowing for one thread-bound Session per factory. {@link SessionFactoryUtils}
* and {@link HibernateTemplate} are aware of thread-bound Sessions and participate
* in such transactions automatically. Using either of those or going through
* implementation for a single Hibernate {@link SessionFactory}.
* Binds a Hibernate Session from the specified factory to the thread,
* potentially allowing for one thread-bound Session per factory.
* {@code SessionFactory.getCurrentSession()} is required for Hibernate
* access code that needs to support this transaction handling mechanism.
* access code that needs to support this transaction handling mechanism,
* with the SessionFactory being configured with {@link SpringSessionContext}.
*
* <p>Supports custom isolation levels, and timeouts that get applied as
* Hibernate transaction timeouts.
@@ -78,27 +75,12 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
*
* <p>Note: To be able to register a DataSource's Connection for plain JDBC code,
* this instance needs to be aware of the DataSource ({@link #setDataSource}).
* The given DataSource should obviously match the one used by the given
* SessionFactory. To achieve this, configure both to the same JNDI DataSource,
* or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and
* a local DataSource (which will be autodetected by this transaction manager).
* The given DataSource should obviously match the one used by the given SessionFactory.
*
* <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
* is necessary for accessing multiple transactional resources within the same
* transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
* such a scenario (see container setup). Normally, JTA setup for Hibernate is
* somewhat container-specific due to the JTA TransactionManager lookup, required
* for proper transactional handling of the SessionFactory-level read-write cache.
*
* <p>Fortunately, there is an easier way with Spring: {@link SessionFactoryUtils}
* (and thus {@link HibernateTemplate}) registers synchronizations with Spring's
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
* (as used by {@link org.springframework.transaction.jta.JtaTransactionManager}),
* for proper after-completion callbacks. Therefore, as long as Spring's
* JtaTransactionManager drives the JTA transactions, Hibernate does not require
* any special configuration for proper JTA participation. Note that there are
* special restrictions with EJB CMT and restrictive JTA subsystems: See
* {@link org.springframework.transaction.jta.JtaTransactionManager}'s javadoc for details.
* such a scenario (see container setup).
*
* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints.
* The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"} flag defaults
@@ -110,27 +92,17 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* support nested transactions! Hence, do not expect Hibernate access code to
* semantically participate in a nested transaction.</i>
*
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
*
* @author Juergen Hoeller
* @since 1.2
* @since 4.2
* @see #setSessionFactory
* @see #setDataSource
* @see LocalSessionFactoryBean
* @see SessionFactoryUtils#getSession
* @see SessionFactoryUtils#applyTransactionTimeout
* @see SessionFactoryUtils#releaseSession
* @see HibernateTemplate
* @see org.hibernate.SessionFactory#getCurrentSession()
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
* @see SessionFactory#getCurrentSession()
* @see DataSourceUtils#getConnection
* @see DataSourceUtils#releaseConnection
* @see org.springframework.jdbc.core.JdbcTemplate
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
*/
@Deprecated
@SuppressWarnings("serial")
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
@@ -143,16 +115,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
private boolean prepareConnection = true;
private boolean allowResultAccessAfterCompletion = false;
private boolean hibernateManagedSession = false;
private boolean earlyFlushBeforeCommit = false;
private Object entityInterceptor;
private SQLExceptionTranslator jdbcExceptionTranslator;
private SQLExceptionTranslator defaultJdbcExceptionTranslator;
/**
* Just needed for entityInterceptorBeanName.
* @see #setEntityInterceptorBeanName
@@ -210,10 +178,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be
* unwrapped to extract its target DataSource.
* @see #setAutodetectDataSource
* @see LocalDataSourceConnectionProvider
* @see LocalSessionFactoryBean#setDataSource
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
* @see org.springframework.jdbc.datasource.DataSourceUtils
* @see TransactionAwareDataSourceProxy
* @see DataSourceUtils
* @see org.springframework.jdbc.core.JdbcTemplate
*/
public void setDataSource(DataSource dataSource) {
@@ -241,7 +207,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* <p>Can be turned off to deliberately ignore an available DataSource, in order
* to not expose Hibernate transactions as JDBC transactions for that DataSource.
* @see #setDataSource
* @see LocalSessionFactoryBean#setDataSource
*/
public void setAutodetectDataSource(boolean autodetectDataSource) {
this.autodetectDataSource = autodetectDataSource;
@@ -257,29 +222,43 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* call {@code Connection.setReadOnly(true)} for read-only transactions
* anymore either. If this flag is turned off, no cleanup of a JDBC Connection
* is required after a transaction, since no Connection settings will get modified.
* @see java.sql.Connection#setTransactionIsolation
* @see java.sql.Connection#setReadOnly
* @see Connection#setTransactionIsolation
* @see Connection#setReadOnly
*/
public void setPrepareConnection(boolean prepareConnection) {
this.prepareConnection = prepareConnection;
}
/**
* Set whether to allow result access after completion, typically via Hibernate's
* ScrollableResults mechanism.
* <p>Default is "false". Turning this flag on enforces over-commit holdability on the
* underlying JDBC Connection (if {@link #prepareConnection "prepareConnection"} is on)
* and skips the disconnect-on-completion step.
* @see Connection#setHoldability
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
* @see #disconnectOnCompletion(Session)
*/
public void setAllowResultAccessAfterCompletion(boolean allowResultAccessAfterCompletion) {
this.allowResultAccessAfterCompletion = allowResultAccessAfterCompletion;
}
/**
* Set whether to operate on a Hibernate-managed Session instead of a
* Spring-managed Session, that is, whether to obtain the Session through
* Hibernate's {@link org.hibernate.SessionFactory#getCurrentSession()}
* instead of {@link org.hibernate.SessionFactory#openSession()} (with a Spring
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
* Hibernate's {@link SessionFactory#getCurrentSession()}
* instead of {@link SessionFactory#openSession()} (with a Spring
* {@link TransactionSynchronizationManager}
* check preceding it).
* <p>Default is "false", i.e. using a Spring-managed Session: taking the current
* thread-bound Session if available (e.g. in an Open-Session-in-View scenario),
* creating a new Session for the current transaction otherwise.
* <p>Switch this flag to "true" in order to enforce use of a Hibernate-managed Session.
* Note that this requires {@link org.hibernate.SessionFactory#getCurrentSession()}
* Note that this requires {@link SessionFactory#getCurrentSession()}
* to always return a proper Session when called for a Spring-managed transaction;
* transaction begin will fail if the {@code getCurrentSession()} call fails.
* <p>This mode will typically be used in combination with a custom Hibernate
* {@link org.hibernate.context.CurrentSessionContext} implementation that stores
* {@link org.hibernate.context.spi.CurrentSessionContext} implementation that stores
* Sessions in a place other than Spring's TransactionSynchronizationManager.
* It may also be used in combination with Spring's Open-Session-in-View support
* (using Spring's default {@link SpringSessionContext}), in which case it subtly
@@ -292,23 +271,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
this.hibernateManagedSession = hibernateManagedSession;
}
/**
* Set whether to perform an early flush before proceeding with a commit.
* <p>Default is "false", performing an implicit flush as part of the actual
* commit step. Switch this to "true" in order to enforce an explicit early
* flush right <i>before</i> the actual commit step.
* <p>An early flush happens before the before-commit synchronization phase,
* making flushed state visible to {@code beforeCommit} callbacks of registered
* {@link org.springframework.transaction.support.TransactionSynchronization}
* objects. Such explicit flush behavior is consistent with Spring-driven
* flushing in a JTA transaction environment, so may also get enforced for
* consistency with JTA transaction behavior.
* @see #prepareForCommit
*/
public void setEarlyFlushBeforeCommit(boolean earlyFlushBeforeCommit) {
this.earlyFlushBeforeCommit = earlyFlushBeforeCommit;
}
/**
* Set the bean name of a Hibernate entity interceptor that allows to inspect
* and change property values before writing to and reading from the database.
@@ -333,12 +295,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* Will get applied to any new Session created by this transaction manager.
* <p>Such an interceptor can either be set at the SessionFactory level,
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
* HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
* It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
* to avoid repeated configuration and guarantee consistent behavior in transactions.
* HibernateTransactionManager.
* @see LocalSessionFactoryBean#setEntityInterceptor
* @see HibernateTemplate#setEntityInterceptor
* @see HibernateInterceptor#setEntityInterceptor
*/
public void setEntityInterceptor(Interceptor entityInterceptor) {
this.entityInterceptor = entityInterceptor;
@@ -370,28 +328,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
}
}
/**
* Set the JDBC exception translator for this transaction manager.
* <p>Applied to any SQLException root cause of a Hibernate JDBCException that
* is thrown on flush, overriding Hibernate's default SQLException translation
* (which is based on Hibernate's Dialect for a specific target database).
* @param jdbcExceptionTranslator the exception translator
* @see java.sql.SQLException
* @see org.hibernate.JDBCException
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
*/
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
}
/**
* Return the JDBC exception translator for this transaction manager, if any.
*/
public SQLExceptionTranslator getJdbcExceptionTranslator() {
return this.jdbcExceptionTranslator;
}
/**
* The bean factory just needs to be known for resolving entity interceptor
* bean names. It does not need to be set for any other mode of operation.
@@ -440,17 +376,15 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" +
SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder);
}
else if (this.hibernateManagedSession) {
try {
Session session = getSessionFactory().getCurrentSession();
Session session = this.sessionFactory.getCurrentSession();
if (logger.isDebugEnabled()) {
logger.debug("Found Hibernate-managed Session [" +
SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
logger.debug("Found Hibernate-managed Session [" + session + "] for Spring-managed transaction");
}
txObject.setExistingSession(session);
}
@@ -477,6 +411,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
}
@Override
@SuppressWarnings("deprecation")
protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
@@ -494,10 +429,10 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Interceptor entityInterceptor = getEntityInterceptor();
Session newSession = (entityInterceptor != null ?
getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
getSessionFactory().openSession());
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
"] for Hibernate transaction");
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
}
txObject.setSession(newSession);
}
@@ -507,12 +442,18 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
// We're allowed to change the transaction settings of the JDBC Connection.
if (logger.isDebugEnabled()) {
logger.debug(
"Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
}
Connection con = session.connection();
Connection con = ((SessionImplementor) session).connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
int currentHoldability = con.getHoldability();
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
txObject.setPreviousHoldability(currentHoldability);
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
}
}
else {
// Not allowed to change the transaction settings of the JDBC Connection.
@@ -521,13 +462,10 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
throw new InvalidIsolationLevelException(
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
"Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +
"Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +
"Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
}
if (logger.isDebugEnabled()) {
logger.debug(
"Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
}
}
@@ -538,8 +476,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
if (!definition.isReadOnly() && !txObject.isNewSession()) {
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT)) {
FlushMode flushMode = SessionFactoryUtils.getFlushMode(session);
if (FlushMode.MANUAL.equals(flushMode)) {
session.setFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
@@ -566,7 +504,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
Connection con = session.connection();
Connection con = ((SessionImplementor) session).connection();
ConnectionHolder conHolder = new ConnectionHolder(con);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
@@ -588,7 +526,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
catch (Throwable ex) {
if (txObject.isNewSession()) {
try {
if (session.getTransaction().isActive()) {
if (session.getTransaction().getStatus() == TransactionStatus.ACTIVE) {
session.getTransaction().rollback();
}
}
@@ -632,32 +570,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
}
}
@Override
protected void prepareForCommit(DefaultTransactionStatus status) {
if (this.earlyFlushBeforeCommit && status.isNewTransaction()) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
Session session = txObject.getSessionHolder().getSession();
if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
logger.debug("Performing an early flush for Hibernate transaction");
try {
session.flush();
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
finally {
session.setFlushMode(FlushMode.MANUAL);
}
}
}
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Committing Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
txObject.getSessionHolder().getSession() + "]");
}
try {
txObject.getSessionHolder().getTransaction().commit();
@@ -677,7 +595,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Rolling back Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
txObject.getSessionHolder().getSession() + "]");
}
try {
txObject.getSessionHolder().getTransaction().rollback();
@@ -703,12 +621,13 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "] rollback-only");
txObject.getSessionHolder().getSession() + "] rollback-only");
}
txObject.setRollbackOnly();
}
@Override
@SuppressWarnings("deprecation")
protected void doCleanupAfterCompletion(Object transaction) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
@@ -723,62 +642,92 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
}
Session session = txObject.getSessionHolder().getSession();
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
if (this.prepareConnection && isPhysicallyConnected(session)) {
// We're running with connection release mode "on_close": We're able to reset
// the isolation level and/or read-only flag of the JDBC Connection here.
// Else, we need to rely on the connection pool to perform proper cleanup.
try {
Connection con = session.connection();
Connection con = ((SessionImplementor) session).connection();
Integer previousHoldability = txObject.getPreviousHoldability();
if (previousHoldability != null) {
con.setHoldability(previousHoldability);
}
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (HibernateException ex) {
logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
}
if (txObject.isNewSession()) {
if (logger.isDebugEnabled()) {
logger.debug("Closing Hibernate Session [" + SessionFactoryUtils.toString(session) +
"] after transaction");
logger.debug("Closing Hibernate Session [" + session + "] after transaction");
}
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
SessionFactoryUtils.closeSession(session);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not closing pre-bound Hibernate Session [" +
SessionFactoryUtils.toString(session) + "] after transaction");
logger.debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
}
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
}
if (!this.hibernateManagedSession) {
session.disconnect();
if (!this.allowResultAccessAfterCompletion && !this.hibernateManagedSession) {
disconnectOnCompletion(session);
}
}
txObject.getSessionHolder().clear();
}
/**
* Disconnect a pre-existing Hibernate Session on transaction completion,
* returning its database connection but preserving its entity state.
* <p>The default implementation simply calls {@link Session#disconnect()}.
* Subclasses may override this with a no-op or with fine-tuned disconnection logic.
* @param session the Hibernate Session to disconnect
* @see Session#disconnect()
*/
protected void disconnectOnCompletion(Session session) {
session.disconnect();
}
/**
* Return whether the given Hibernate Session will always hold the same
* JDBC Connection. This is used to check whether the transaction manager
* can safely prepare and clean up the JDBC Connection used for a transaction.
* <p>Default implementation checks the Session's connection release mode
* to be "on_close". Unfortunately, this requires casting to SessionImpl,
* as of Hibernate 3.1. If that cast doesn't work, we'll simply assume
* we're safe and return {@code true}.
* <p>The default implementation checks the Session's connection release mode
* to be "on_close".
* @param session the Hibernate Session to check
* @see org.hibernate.impl.SessionImpl#getConnectionReleaseMode()
* @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
* @see ConnectionReleaseMode#ON_CLOSE
*/
@SuppressWarnings("deprecation")
protected boolean isSameConnectionForEntireSession(Session session) {
if (!(session instanceof SessionImpl)) {
if (!(session instanceof SessionImplementor)) {
// The best we can do is to assume we're safe.
return true;
}
ConnectionReleaseMode releaseMode = ((SessionImpl) session).getConnectionReleaseMode();
ConnectionReleaseMode releaseMode =
((SessionImplementor) session).getJdbcCoordinator().getConnectionReleaseMode();
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
}
/**
* Determine whether the given Session is (still) physically connected
* to the database, that is, holds an active JDBC Connection internally.
* @param session the Hibernate Session to check
* @see #isSameConnectionForEntireSession(Session)
*/
protected boolean isPhysicallyConnected(Session session) {
if (!(session instanceof SessionImplementor)) {
// The best we can do is to check whether we're logically connected.
return session.isConnected();
}
return ((SessionImplementor) session).getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
}
/**
* Convert the given HibernateException to an appropriate exception
@@ -788,48 +737,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* @param ex HibernateException that occurred
* @return a corresponding DataAccessException
* @see SessionFactoryUtils#convertHibernateAccessException
* @see #setJdbcExceptionTranslator
*/
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
}
else if (GenericJDBCException.class == ex.getClass()) {
return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
}
return SessionFactoryUtils.convertHibernateAccessException(ex);
}
/**
* Convert the given Hibernate JDBCException to an appropriate exception
* from the {@code org.springframework.dao} hierarchy, using the
* given SQLExceptionTranslator.
* @param ex Hibernate JDBCException that occurred
* @param translator the SQLExceptionTranslator to use
* @return a corresponding DataAccessException
*/
protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
return translator.translate("Hibernate flushing: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
}
/**
* Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
* <p>Creates a default
* {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
* for the SessionFactory's underlying DataSource.
*/
protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
if (this.defaultJdbcExceptionTranslator == null) {
if (getDataSource() != null) {
this.defaultJdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(getDataSource());
}
else {
this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
}
}
return this.defaultJdbcExceptionTranslator;
}
/**
* Hibernate transaction object, representing a SessionHolder.
@@ -843,6 +755,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
private boolean newSession;
private Integer previousHoldability;
public void setSession(Session session) {
this.sessionHolder = new SessionHolder(session);
this.newSessionHolder = true;
@@ -873,12 +787,21 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
return this.newSession;
}
public void setPreviousHoldability(Integer previousHoldability) {
this.previousHoldability = previousHoldability;
}
public Integer getPreviousHoldability() {
return this.previousHoldability;
}
public boolean hasSpringManagedTransaction() {
return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
}
public boolean hasHibernateManagedTransaction() {
return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());
return (this.sessionHolder != null &&
this.sessionHolder.getSession().getTransaction().getStatus() == TransactionStatus.ACTIVE);
}
public void setRollbackOnly() {

View File

@@ -0,0 +1,539 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.Interceptor;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.Assert;
/**
* {@link FactoryBean} that creates a Hibernate
* {@link SessionFactory}. This is the usual way to set up a shared
* Hibernate SessionFactory in a Spring application context; the SessionFactory can
* then be passed to Hibernate-based data access objects via dependency injection.
*
* <p>Compatible with Hibernate 5.0/5.1 as well as 5.2, as of Spring 4.3.
*
* @author Juergen Hoeller
* @since 4.2
* @see #setDataSource
* @see #setPackagesToScan
* @see LocalSessionFactoryBuilder
*/
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
implements FactoryBean<SessionFactory>, ResourceLoaderAware, InitializingBean, DisposableBean {
private DataSource dataSource;
private Resource[] configLocations;
private String[] mappingResources;
private Resource[] mappingLocations;
private Resource[] cacheableMappingLocations;
private Resource[] mappingJarLocations;
private Resource[] mappingDirectoryLocations;
private Interceptor entityInterceptor;
private ImplicitNamingStrategy implicitNamingStrategy;
private PhysicalNamingStrategy physicalNamingStrategy;
private Object jtaTransactionManager;
private MultiTenantConnectionProvider multiTenantConnectionProvider;
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
private TypeFilter[] entityTypeFilters;
private Properties hibernateProperties;
private Class<?>[] annotatedClasses;
private String[] annotatedPackages;
private String[] packagesToScan;
private AsyncTaskExecutor bootstrapExecutor;
private MetadataSources metadataSources;
private ResourcePatternResolver resourcePatternResolver;
private Configuration configuration;
private SessionFactory sessionFactory;
/**
* Set the DataSource to be used by the SessionFactory.
* If set, this will override corresponding settings in Hibernate properties.
* <p>If this is set, the Hibernate settings should not define
* a connection provider to avoid meaningless double configuration.
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Set the location of a single Hibernate XML config file, for example as
* classpath resource "classpath:hibernate.cfg.xml".
* <p>Note: Can be omitted when all necessary properties and mapping
* resources are specified locally via this bean.
* @see Configuration#configure(java.net.URL)
*/
public void setConfigLocation(Resource configLocation) {
this.configLocations = new Resource[] {configLocation};
}
/**
* Set the locations of multiple Hibernate XML config files, for example as
* classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
* <p>Note: Can be omitted when all necessary properties and mapping
* resources are specified locally via this bean.
* @see Configuration#configure(java.net.URL)
*/
public void setConfigLocations(Resource... configLocations) {
this.configLocations = configLocations;
}
/**
* Set Hibernate mapping resources to be found in the class path,
* like "example.hbm.xml" or "mypackage/example.hbm.xml".
* Analogous to mapping entries in a Hibernate XML config file.
* Alternative to the more generic setMappingLocations method.
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see #setMappingLocations
* @see Configuration#addResource
*/
public void setMappingResources(String... mappingResources) {
this.mappingResources = mappingResources;
}
/**
* Set locations of Hibernate mapping files, for example as classpath
* resource "classpath:example.hbm.xml". Supports any resource location
* via Spring's resource abstraction, for example relative paths like
* "WEB-INF/mappings/example.hbm.xml" when running in an application context.
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see Configuration#addInputStream
*/
public void setMappingLocations(Resource... mappingLocations) {
this.mappingLocations = mappingLocations;
}
/**
* Set locations of cacheable Hibernate mapping files, for example as web app
* resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
* via Spring's resource abstraction, as long as the resource can be resolved
* in the file system.
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see Configuration#addCacheableFile(File)
*/
public void setCacheableMappingLocations(Resource... cacheableMappingLocations) {
this.cacheableMappingLocations = cacheableMappingLocations;
}
/**
* Set locations of jar files that contain Hibernate mapping resources,
* like "WEB-INF/lib/example.hbm.jar".
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see Configuration#addJar(File)
*/
public void setMappingJarLocations(Resource... mappingJarLocations) {
this.mappingJarLocations = mappingJarLocations;
}
/**
* Set locations of directories that contain Hibernate mapping resources,
* like "WEB-INF/mappings".
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see Configuration#addDirectory(File)
*/
public void setMappingDirectoryLocations(Resource... mappingDirectoryLocations) {
this.mappingDirectoryLocations = mappingDirectoryLocations;
}
/**
* Set a Hibernate entity interceptor that allows to inspect and change
* property values before writing to and reading from the database.
* Will get applied to any new Session created by this factory.
* @see Configuration#setInterceptor
*/
public void setEntityInterceptor(Interceptor entityInterceptor) {
this.entityInterceptor = entityInterceptor;
}
/**
* Set a Hibernate 5.0 ImplicitNamingStrategy for the SessionFactory.
* @see Configuration#setImplicitNamingStrategy
*/
public void setImplicitNamingStrategy(ImplicitNamingStrategy implicitNamingStrategy) {
this.implicitNamingStrategy = implicitNamingStrategy;
}
/**
* Set a Hibernate 5.0 PhysicalNamingStrategy for the SessionFactory.
* @see Configuration#setPhysicalNamingStrategy
*/
public void setPhysicalNamingStrategy(PhysicalNamingStrategy physicalNamingStrategy) {
this.physicalNamingStrategy = physicalNamingStrategy;
}
/**
* Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
* or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
* if any. Implicitly sets up {@code JtaPlatform}.
* @see LocalSessionFactoryBuilder#setJtaTransactionManager
*/
public void setJtaTransactionManager(Object jtaTransactionManager) {
this.jtaTransactionManager = jtaTransactionManager;
}
/**
* Set a {@link MultiTenantConnectionProvider} to be passed on to the SessionFactory.
* @since 4.3
* @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider
*/
public void setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) {
this.multiTenantConnectionProvider = multiTenantConnectionProvider;
}
/**
* Set a {@link CurrentTenantIdentifierResolver} to be passed on to the SessionFactory.
* @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver
*/
public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
}
/**
* Specify custom type filters for Spring-based scanning for entity classes.
* <p>Default is to search all specified packages for classes annotated with
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
* or {@code @javax.persistence.MappedSuperclass}.
* @see #setPackagesToScan
*/
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
this.entityTypeFilters = entityTypeFilters;
}
/**
* Set Hibernate properties, such as "hibernate.dialect".
* <p>Note: Do not specify a transaction provider here when using
* Spring-driven transactions. It is also advisable to omit connection
* provider settings and use a Spring-set DataSource instead.
* @see #setDataSource
*/
public void setHibernateProperties(Properties hibernateProperties) {
this.hibernateProperties = hibernateProperties;
}
/**
* Return the Hibernate properties, if any. Mainly available for
* configuration through property paths that specify individual keys.
*/
public Properties getHibernateProperties() {
if (this.hibernateProperties == null) {
this.hibernateProperties = new Properties();
}
return this.hibernateProperties;
}
/**
* Specify annotated entity classes to register with this Hibernate SessionFactory.
* @see Configuration#addAnnotatedClass(Class)
*/
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
this.annotatedClasses = annotatedClasses;
}
/**
* Specify the names of annotated packages, for which package-level
* annotation metadata will be read.
* @see Configuration#addPackage(String)
*/
public void setAnnotatedPackages(String... annotatedPackages) {
this.annotatedPackages = annotatedPackages;
}
/**
* Specify packages to search for autodetection of your entity classes in the
* classpath. This is analogous to Spring's component-scan feature
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
*/
public void setPackagesToScan(String... packagesToScan) {
this.packagesToScan = packagesToScan;
}
/**
* Specify an asynchronous executor for background bootstrapping,
* e.g. a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
* <p>{@code SessionFactory} initialization will then switch into background
* bootstrap mode, with a {@code SessionFactory} proxy immediately returned for
* injection purposes instead of waiting for Hibernate's bootstrapping to complete.
* However, note that the first actual call to a {@code SessionFactory} method will
* then block until Hibernate's bootstrapping completed, if not ready by then.
* For maximum benefit, make sure to avoid early {@code SessionFactory} calls
* in init methods of related beans, even for metadata introspection purposes.
* @see LocalSessionFactoryBuilder#buildSessionFactory(AsyncTaskExecutor)
* @since 4.3
*/
public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) {
this.bootstrapExecutor = bootstrapExecutor;
}
/**
* Specify a Hibernate {@link MetadataSources} service to use (e.g. reusing an
* existing one), potentially populated with a custom Hibernate bootstrap
* {@link org.hibernate.service.ServiceRegistry} as well.
* @since 4.3
*/
public void setMetadataSources(MetadataSources metadataSources) {
Assert.notNull(metadataSources, "MetadataSources must not be null");
this.metadataSources = metadataSources;
}
/**
* Determine the Hibernate {@link MetadataSources} to use.
* <p>Can also be externally called to initialize and pre-populate a {@link MetadataSources}
* instance which is then going to be used for {@link SessionFactory} building.
* @return the MetadataSources to use (never {@code null})
* @since 4.3
* @see LocalSessionFactoryBuilder#LocalSessionFactoryBuilder(DataSource, ResourceLoader, MetadataSources)
*/
public MetadataSources getMetadataSources() {
if (this.metadataSources == null) {
BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder();
if (this.resourcePatternResolver != null) {
builder = builder.applyClassLoader(this.resourcePatternResolver.getClassLoader());
}
this.metadataSources = new MetadataSources(builder.build());
}
return this.metadataSources;
}
/**
* Specify a Spring {@link ResourceLoader} to use for Hibernate metadata.
* @param resourceLoader the ResourceLoader to use (never {@code null})
*/
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
/**
* Determine the Spring {@link ResourceLoader} to use for Hibernate metadata.
* @return the ResourceLoader to use (never {@code null})
* @since 4.3
*/
public ResourceLoader getResourceLoader() {
if (this.resourcePatternResolver == null) {
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
}
return this.resourcePatternResolver;
}
@Override
public void afterPropertiesSet() throws IOException {
LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(
this.dataSource, getResourceLoader(), getMetadataSources());
if (this.configLocations != null) {
for (Resource resource : this.configLocations) {
// Load Hibernate configuration from given location.
sfb.configure(resource.getURL());
}
}
if (this.mappingResources != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (String mapping : this.mappingResources) {
Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader());
sfb.addInputStream(mr.getInputStream());
}
}
if (this.mappingLocations != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (Resource resource : this.mappingLocations) {
sfb.addInputStream(resource.getInputStream());
}
}
if (this.cacheableMappingLocations != null) {
// Register given cacheable Hibernate mapping definitions, read from the file system.
for (Resource resource : this.cacheableMappingLocations) {
sfb.addCacheableFile(resource.getFile());
}
}
if (this.mappingJarLocations != null) {
// Register given Hibernate mapping definitions, contained in jar files.
for (Resource resource : this.mappingJarLocations) {
sfb.addJar(resource.getFile());
}
}
if (this.mappingDirectoryLocations != null) {
// Register all Hibernate mapping definitions in the given directories.
for (Resource resource : this.mappingDirectoryLocations) {
File file = resource.getFile();
if (!file.isDirectory()) {
throw new IllegalArgumentException(
"Mapping directory location [" + resource + "] does not denote a directory");
}
sfb.addDirectory(file);
}
}
if (this.entityInterceptor != null) {
sfb.setInterceptor(this.entityInterceptor);
}
if (this.implicitNamingStrategy != null) {
sfb.setImplicitNamingStrategy(this.implicitNamingStrategy);
}
if (this.physicalNamingStrategy != null) {
sfb.setPhysicalNamingStrategy(this.physicalNamingStrategy);
}
if (this.jtaTransactionManager != null) {
sfb.setJtaTransactionManager(this.jtaTransactionManager);
}
if (this.multiTenantConnectionProvider != null) {
sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider);
}
if (this.currentTenantIdentifierResolver != null) {
sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver);
}
if (this.entityTypeFilters != null) {
sfb.setEntityTypeFilters(this.entityTypeFilters);
}
if (this.hibernateProperties != null) {
sfb.addProperties(this.hibernateProperties);
}
if (this.annotatedClasses != null) {
sfb.addAnnotatedClasses(this.annotatedClasses);
}
if (this.annotatedPackages != null) {
sfb.addPackages(this.annotatedPackages);
}
if (this.packagesToScan != null) {
sfb.scanPackages(this.packagesToScan);
}
// Build SessionFactory instance.
this.configuration = sfb;
this.sessionFactory = buildSessionFactory(sfb);
}
/**
* Subclasses can override this method to perform custom initialization
* of the SessionFactory instance, creating it via the given Configuration
* object that got prepared by this LocalSessionFactoryBean.
* <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
* A custom implementation could prepare the instance in a specific way (e.g. applying
* a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
* @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
* @return the SessionFactory instance
* @see LocalSessionFactoryBuilder#buildSessionFactory
*/
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
return (this.bootstrapExecutor != null ? sfb.buildSessionFactory(this.bootstrapExecutor) :
sfb.buildSessionFactory());
}
/**
* Return the Hibernate Configuration object used to build the SessionFactory.
* Allows for access to configuration metadata stored there (rarely needed).
* @throws IllegalStateException if the Configuration object has not been initialized yet
*/
public final Configuration getConfiguration() {
if (this.configuration == null) {
throw new IllegalStateException("Configuration not initialized yet");
}
return this.configuration;
}
@Override
public SessionFactory getObject() {
return this.sessionFactory;
}
@Override
public Class<?> getObjectType() {
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void destroy() {
this.sessionFactory.close();
}
}

View File

@@ -0,0 +1,397 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.springframework.core.InfrastructureProxy;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A Spring-provided extension of the standard Hibernate {@link Configuration} class,
* adding {@link SpringSessionContext} as a default and providing convenient ways
* to specify a DataSource and an application class loader.
*
* <p>This is designed for programmatic use, e.g. in {@code @Bean} factory methods.
* Consider using {@link LocalSessionFactoryBean} for XML bean definition files.
*
* <p>Compatible with Hibernate 5.0/5.1 as well as 5.2, as of Spring 4.3.
*
* @author Juergen Hoeller
* @since 4.2
* @see LocalSessionFactoryBean
*/
@SuppressWarnings("serial")
public class LocalSessionFactoryBuilder extends Configuration {
private static final String RESOURCE_PATTERN = "/**/*.class";
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {
new AnnotationTypeFilter(Entity.class, false),
new AnnotationTypeFilter(Embeddable.class, false),
new AnnotationTypeFilter(MappedSuperclass.class, false)};
private final TypeFilter CONVERTER_TYPE_FILTER = new AnnotationTypeFilter(Converter.class, false);
private final ResourcePatternResolver resourcePatternResolver;
private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS;
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
*/
public LocalSessionFactoryBuilder(DataSource dataSource) {
this(dataSource, new PathMatchingResourcePatternResolver());
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
* @param classLoader the ClassLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
* @param resourceLoader the ResourceLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
this(dataSource, resourceLoader, new MetadataSources(
new BootstrapServiceRegistryBuilder().applyClassLoader(resourceLoader.getClassLoader()).build()));
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
* @param resourceLoader the ResourceLoader to load application classes from
* @param metadataSources the Hibernate MetadataSources service to use (e.g. reusing an existing one)
* @since 4.3
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader, MetadataSources metadataSources) {
super(metadataSources);
getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
if (dataSource != null) {
getProperties().put(Environment.DATASOURCE, dataSource);
}
// Hibernate 5.2: manually enforce connection release mode ON_CLOSE (the former default)
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD");
getProperties().put(AvailableSettings.CLASSLOADERS, Collections.singleton(resourceLoader.getClassLoader()));
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
/**
* Set the Spring {@link JtaTransactionManager} or the JTA {@link TransactionManager}
* to be used with Hibernate, if any. Allows for using a Spring-managed transaction
* manager for Hibernate 5's session and cache synchronization, with the
* "hibernate.transaction.jta.platform" automatically set to it.
* <p>A passed-in Spring {@link JtaTransactionManager} needs to contain a JTA
* {@link TransactionManager} reference to be usable here, except for the WebSphere
* case where we'll automatically set {@code WebSphereExtendedJtaPlatform} accordingly.
* <p>Note: If this is set, the Hibernate settings should not contain a JTA platform
* setting to avoid meaningless double configuration.
*/
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
if (jtaTransactionManager instanceof JtaTransactionManager) {
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
if (webspherePresent) {
getProperties().put(AvailableSettings.JTA_PLATFORM,
"org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform");
}
else {
JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
if (jtaTm.getTransactionManager() == null) {
throw new IllegalArgumentException(
"Can only apply JtaTransactionManager which has a TransactionManager reference set");
}
getProperties().put(AvailableSettings.JTA_PLATFORM,
new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction(),
jtaTm.getTransactionSynchronizationRegistry()));
}
}
else if (jtaTransactionManager instanceof TransactionManager) {
getProperties().put(AvailableSettings.JTA_PLATFORM,
new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null, null));
}
else {
throw new IllegalArgumentException(
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
}
// Hibernate 5.2: manually enforce connection release mode AFTER_STATEMENT (the JTA default)
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT");
return this;
}
/**
* Set a {@link MultiTenantConnectionProvider} to be passed on to the SessionFactory.
* @since 4.3
* @see AvailableSettings#MULTI_TENANT_CONNECTION_PROVIDER
*/
public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) {
getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
return this;
}
/**
* Specify custom type filters for Spring-based scanning for entity classes.
* <p>Default is to search all specified packages for classes annotated with
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
* or {@code @javax.persistence.MappedSuperclass}.
* @see #scanPackages
*/
public LocalSessionFactoryBuilder setEntityTypeFilters(TypeFilter... entityTypeFilters) {
this.entityTypeFilters = entityTypeFilters;
return this;
}
/**
* Add the given annotated classes in a batch.
* @see #addAnnotatedClass
* @see #scanPackages
*/
public LocalSessionFactoryBuilder addAnnotatedClasses(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
addAnnotatedClass(annotatedClass);
}
return this;
}
/**
* Add the given annotated packages in a batch.
* @see #addPackage
* @see #scanPackages
*/
public LocalSessionFactoryBuilder addPackages(String... annotatedPackages) {
for (String annotatedPackage : annotatedPackages) {
addPackage(annotatedPackage);
}
return this;
}
/**
* Perform Spring-based scanning for entity classes, registering them
* as annotated classes with this {@code Configuration}.
* @param packagesToScan one or more Java package names
* @throws HibernateException if scanning fails for any reason
*/
@SuppressWarnings("unchecked")
public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException {
Set<String> entityClassNames = new TreeSet<String>();
Set<String> converterClassNames = new TreeSet<String>();
Set<String> packageNames = new TreeSet<String>();
try {
for (String pkg : packagesToScan) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
if (matchesEntityTypeFilter(reader, readerFactory)) {
entityClassNames.add(className);
}
else if (CONVERTER_TYPE_FILTER.match(reader, readerFactory)) {
converterClassNames.add(className);
}
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
}
}
}
}
}
catch (IOException ex) {
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
}
try {
ClassLoader cl = this.resourcePatternResolver.getClassLoader();
for (String className : entityClassNames) {
addAnnotatedClass(cl.loadClass(className));
}
for (String className : converterClassNames) {
addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) cl.loadClass(className));
}
for (String packageName : packageNames) {
addPackage(packageName);
}
}
catch (ClassNotFoundException ex) {
throw new MappingException("Failed to load annotated classes from classpath", ex);
}
return this;
}
/**
* Check whether any of the configured entity type filters matches
* the current class descriptor contained in the metadata reader.
*/
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
if (this.entityTypeFilters != null) {
for (TypeFilter filter : this.entityTypeFilters) {
if (filter.match(reader, readerFactory)) {
return true;
}
}
}
return false;
}
/**
* Build the Hibernate {@code SessionFactory} through background bootstrapping,
* using the given executor for a parallel initialization phase
* (e.g. a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}).
* <p>{@code SessionFactory} initialization will then switch into background
* bootstrap mode, with a {@code SessionFactory} proxy immediately returned for
* injection purposes instead of waiting for Hibernate's bootstrapping to complete.
* However, note that the first actual call to a {@code SessionFactory} method will
* then block until Hibernate's bootstrapping completed, if not ready by then.
* For maximum benefit, make sure to avoid early {@code SessionFactory} calls
* in init methods of related beans, even for metadata introspection purposes.
* @since 4.3
* @see #buildSessionFactory()
*/
public SessionFactory buildSessionFactory(AsyncTaskExecutor bootstrapExecutor) {
Assert.notNull(bootstrapExecutor, "AsyncTaskExecutor must not be null");
return (SessionFactory) Proxy.newProxyInstance(this.resourcePatternResolver.getClassLoader(),
new Class<?>[] {SessionFactoryImplementor.class, InfrastructureProxy.class},
new BootstrapSessionFactoryInvocationHandler(bootstrapExecutor));
}
/**
* Proxy invocation handler for background bootstrapping, only enforcing
* a fully initialized target {@code SessionFactory} when actually needed.
* @since 4.3
*/
private class BootstrapSessionFactoryInvocationHandler implements InvocationHandler {
private final Future<SessionFactory> sessionFactoryFuture;
public BootstrapSessionFactoryInvocationHandler(AsyncTaskExecutor bootstrapExecutor) {
this.sessionFactoryFuture = bootstrapExecutor.submit(new Callable<SessionFactory>() {
@Override
public SessionFactory call() throws Exception {
return buildSessionFactory();
}
});
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (method.getName().equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
}
else if (method.getName().equals("hashCode")) {
// Use hashCode of EntityManagerFactory proxy.
return System.identityHashCode(proxy);
}
else if (method.getName().equals("getProperties")) {
return getProperties();
}
else if (method.getName().equals("getWrappedObject")) {
// Call coming in through InfrastructureProxy interface...
return getSessionFactory();
}
// Regular delegation to the target SessionFactory,
// enforcing its full initialization...
return method.invoke(getSessionFactory(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
private SessionFactory getSessionFactory() {
try {
return this.sessionFactoryFuture.get();
}
catch (InterruptedException ex) {
throw new IllegalStateException("Interrupted during initialization of Hibernate SessionFactory: " +
ex.getMessage());
}
catch (ExecutionException ex) {
throw new IllegalStateException("Failed to asynchronously initialize Hibernate SessionFactory: " +
ex.getMessage(), ex.getCause());
}
}
}
}

View File

@@ -0,0 +1,267 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import java.lang.reflect.Method;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.PersistentObjectException;
import org.hibernate.PessimisticLockException;
import org.hibernate.PropertyValueException;
import org.hibernate.QueryException;
import org.hibernate.QueryTimeoutException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.hibernate.dialect.lock.PessimisticEntityLockException;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.DataException;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.service.UnknownServiceException;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Helper class featuring methods for Hibernate Session handling.
* Also provides support for exception translation.
*
* <p>Used internally by {@link HibernateTransactionManager}.
* Can also be used directly in application code.
*
* @author Juergen Hoeller
* @since 4.2
* @see HibernateExceptionTranslator
* @see HibernateTransactionManager
*/
public abstract class SessionFactoryUtils {
/**
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
* Returns {@code DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100}
* to execute Session cleanup before JDBC Connection cleanup, if any.
* @see DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
*/
public static final int SESSION_SYNCHRONIZATION_ORDER =
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
private static Method getFlushMode;
static {
try {
// Hibernate 5.2+ getHibernateFlushMode()
getFlushMode = Session.class.getMethod("getHibernateFlushMode");
}
catch (NoSuchMethodException ex) {
try {
// Hibernate 5.0/5.1 getFlushMode() with FlushMode return type
getFlushMode = Session.class.getMethod("getFlushMode");
}
catch (NoSuchMethodException ex2) {
throw new IllegalStateException("No compatible Hibernate getFlushMode signature found", ex2);
}
}
// Check that it is the Hibernate FlushMode type, not JPA's...
Assert.state(FlushMode.class == getFlushMode.getReturnType());
}
/**
* Get the native Hibernate FlushMode, adapting between Hibernate 5.0/5.1 and 5.2+.
* @param session the Hibernate Session to get the flush mode from
* @return the FlushMode (never {@code null})
* @since 4.3
*/
static FlushMode getFlushMode(Session session) {
return (FlushMode) ReflectionUtils.invokeMethod(getFlushMode, session);
}
/**
* Perform actual closing of the Hibernate Session,
* catching and logging any cleanup exceptions thrown.
* @param session the Hibernate Session to close (may be {@code null})
* @see Session#close()
*/
public static void closeSession(Session session) {
if (session != null) {
try {
session.close();
}
catch (HibernateException ex) {
logger.debug("Could not close Hibernate Session", ex);
}
catch (Throwable ex) {
logger.debug("Unexpected exception on closing Hibernate Session", ex);
}
}
}
/**
* Determine the DataSource of the given SessionFactory.
* @param sessionFactory the SessionFactory to check
* @return the DataSource, or {@code null} if none found
* @see ConnectionProvider
*/
public static DataSource getDataSource(SessionFactory sessionFactory) {
Method getProperties = ClassUtils.getMethodIfAvailable(sessionFactory.getClass(), "getProperties");
if (getProperties != null) {
Map<?, ?> props = (Map<?, ?>) ReflectionUtils.invokeMethod(getProperties, sessionFactory);
Object dataSourceValue = props.get(Environment.DATASOURCE);
if (dataSourceValue instanceof DataSource) {
return (DataSource) dataSourceValue;
}
}
if (sessionFactory instanceof SessionFactoryImplementor) {
SessionFactoryImplementor sfi = (SessionFactoryImplementor) sessionFactory;
try {
ConnectionProvider cp = sfi.getServiceRegistry().getService(ConnectionProvider.class);
if (cp != null) {
return cp.unwrap(DataSource.class);
}
}
catch (UnknownServiceException ex) {
if (logger.isDebugEnabled()) {
logger.debug("No ConnectionProvider found - cannot determine DataSource for SessionFactory: " + ex);
}
}
}
return null;
}
/**
* Convert the given HibernateException to an appropriate exception
* from the {@code org.springframework.dao} hierarchy.
* @param ex HibernateException that occurred
* @return the corresponding DataAccessException instance
* @see HibernateExceptionTranslator#convertHibernateAccessException
* @see HibernateTransactionManager#convertHibernateAccessException
*/
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
if (ex instanceof JDBCConnectionException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof SQLGrammarException) {
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof QueryTimeoutException) {
QueryTimeoutException jdbcEx = (QueryTimeoutException) ex;
return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof LockAcquisitionException) {
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof PessimisticLockException) {
PessimisticLockException jdbcEx = (PessimisticLockException) ex;
return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof ConstraintViolationException) {
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
}
if (ex instanceof DataException) {
DataException jdbcEx = (DataException) ex;
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof JDBCException) {
return new HibernateJdbcException((JDBCException) ex);
}
// end of JDBCException (subclass) handling
if (ex instanceof QueryException) {
return new HibernateQueryException((QueryException) ex);
}
if (ex instanceof NonUniqueResultException) {
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
}
if (ex instanceof NonUniqueObjectException) {
return new DuplicateKeyException(ex.getMessage(), ex);
}
if (ex instanceof PropertyValueException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
if (ex instanceof PersistentObjectException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof TransientObjectException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof ObjectDeletedException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof UnresolvableObjectException) {
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
}
if (ex instanceof WrongClassException) {
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
}
if (ex instanceof StaleObjectStateException) {
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
}
if (ex instanceof StaleStateException) {
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
}
if (ex instanceof OptimisticEntityLockException) {
return new HibernateOptimisticLockingFailureException((OptimisticEntityLockException) ex);
}
if (ex instanceof PessimisticEntityLockException) {
if (ex.getCause() instanceof LockAcquisitionException) {
return new CannotAcquireLockException(ex.getMessage(), ex.getCause());
}
return new PessimisticLockingFailureException(ex.getMessage(), ex);
}
// fallback
return new HibernateSystemException(ex);
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
* HibernateTransactionManager binds instances of this class to the thread,
* for a given SessionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Juergen Hoeller
* @since 4.2
* @see HibernateTransactionManager
* @see SessionFactoryUtils
*/
public class SessionHolder extends ResourceHolderSupport {
private Session session;
private Transaction transaction;
private FlushMode previousFlushMode;
public SessionHolder(Session session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
public Session getSession() {
return this.session;
}
public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}
public Transaction getTransaction() {
return this.transaction;
}
public void setPreviousFlushMode(FlushMode previousFlushMode) {
this.previousFlushMode = previousFlushMode;
}
public FlushMode getPreviousFlushMode() {
return this.previousFlushMode;
}
@Override
public void clear() {
super.clear();
this.transaction = null;
this.previousFlushMode = null;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
/**
* Simple synchronization adapter that propagates a {@code flush()} call
* to the underlying Hibernate Session. Used in combination with JTA.
*
* @author Juergen Hoeller
* @since 4.2
*/
public class SpringFlushSynchronization extends TransactionSynchronizationAdapter {
private final Session session;
public SpringFlushSynchronization(Session session) {
this.session = session;
}
@Override
public void flush() {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
this.session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
@Override
public boolean equals(Object obj) {
return (obj instanceof SpringFlushSynchronization &&
this.session == ((SpringFlushSynchronization) obj).session);
}
@Override
public int hashCode() {
return this.session.hashCode();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.internal.JTASessionContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Spring-specific subclass of Hibernate's JTASessionContext,
* setting {@code FlushMode.MANUAL} for read-only transactions.
*
* @author Juergen Hoeller
* @since 4.2
*/
@SuppressWarnings("serial")
public class SpringJtaSessionContext extends JTASessionContext {
public SpringJtaSessionContext(SessionFactoryImplementor factory) {
super(factory);
}
@Override
@SuppressWarnings("deprecation")
protected Session buildOrObtainSession() {
Session session = super.buildOrObtainSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
return session;
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Implementation of Hibernate 3.1's CurrentSessionContext interface
* that delegates to Spring's SessionFactoryUtils for providing a
* Spring-managed current Session.
*
* <p>This CurrentSessionContext implementation can also be specified in custom
* SessionFactory setup through the "hibernate.current_session_context_class"
* property, with the fully qualified name of this class as value.
*
* @author Juergen Hoeller
* @since 4.2
*/
@SuppressWarnings("serial")
public class SpringSessionContext implements CurrentSessionContext {
private final SessionFactoryImplementor sessionFactory;
private TransactionManager transactionManager;
private CurrentSessionContext jtaSessionContext;
/**
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
* @param sessionFactory the SessionFactory to provide current Sessions for
*/
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
try {
JtaPlatform jtaPlatform = sessionFactory.getServiceRegistry().getService(JtaPlatform.class);
this.transactionManager = jtaPlatform.retrieveTransactionManager();
if (this.transactionManager != null) {
this.jtaSessionContext = new SpringJtaSessionContext(sessionFactory);
}
}
catch (Exception ex) {
LogFactory.getLog(SpringSessionContext.class).warn(
"Could not introspect Hibernate JtaPlatform for SpringJtaSessionContext", ex);
}
}
/**
* Retrieve the Spring-managed Session for the current thread, if any.
*/
@Override
@SuppressWarnings("deprecation")
public Session currentSession() throws HibernateException {
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
if (value instanceof Session) {
return (Session) value;
}
else if (value instanceof SessionHolder) {
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (!sessionHolder.isSynchronizedWithTransaction() &&
TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
FlushMode flushMode = SessionFactoryUtils.getFlushMode(session);
if (flushMode.equals(FlushMode.MANUAL) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return session;
}
if (this.transactionManager != null) {
try {
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
}
return session;
}
}
catch (SystemException ex) {
throw new HibernateException("JTA TransactionManager found but status check failed", ex);
}
}
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Session session = this.sessionFactory.openSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
sessionHolder.setSynchronizedWithTransaction(true);
return session;
}
else {
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Callback for resource cleanup at the end of a Spring-managed transaction
* for a pre-bound Hibernate Session.
*
* @author Juergen Hoeller
* @since 4.2
*/
public class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
private final SessionHolder sessionHolder;
private final SessionFactory sessionFactory;
private final boolean newSession;
private boolean holderActive = true;
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) {
this(sessionHolder, sessionFactory, false);
}
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) {
this.sessionHolder = sessionHolder;
this.sessionFactory = sessionFactory;
this.newSession = newSession;
}
private Session getCurrentSession() {
return this.sessionHolder.getSession();
}
@Override
public int getOrder() {
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
}
@Override
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
getCurrentSession().disconnect();
}
}
@Override
public void resume() {
if (this.holderActive) {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
@Override
public void flush() {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
getCurrentSession().flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
@Override
public void beforeCommit(boolean readOnly) throws DataAccessException {
if (!readOnly) {
Session session = getCurrentSession();
// Read-write transaction -> flush the Hibernate Session.
// Further check: only flush when not FlushMode.MANUAL.
if (!FlushMode.MANUAL.equals(SessionFactoryUtils.getFlushMode(session))) {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
}
}
@Override
@SuppressWarnings("deprecation")
public void beforeCompletion() {
try {
Session session = this.sessionHolder.getSession();
if (this.sessionHolder.getPreviousFlushMode() != null) {
// In case of pre-bound Session, restore previous flush mode.
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
}
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
session.disconnect();
}
finally {
// Unbind at this point if it's a new Session...
if (this.newSession) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
this.holderActive = false;
}
}
}
@Override
public void afterCommit() {
}
@Override
public void afterCompletion(int status) {
try {
if (status != STATUS_COMMITTED) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
this.sessionHolder.getSession().clear();
}
}
finally {
this.sessionHolder.setSynchronizedWithTransaction(false);
// Call close() at this point if it's a new Session...
if (this.newSession) {
SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
}
}
}
}

View File

@@ -0,0 +1,13 @@
/**
* Package providing integration of
* <a href="http://www.hibernate.org">Hibernate 5.x</a>
* with Spring concepts.
*
* <p>Contains an implementation of Spring's transaction SPI for local Hibernate transactions.
* This package is intentionally rather minimal, with no template classes or the like,
* in order to follow Hibernate recommendations as closely as possible. We recommend
* using Hibernate's native <code>sessionFactory.getCurrentSession()</code> style.
*
* <p><b>This package supports Hibernate 5.x only.</b>
*/
package org.springframework.orm.hibernate5;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
package org.springframework.orm.hibernate5.support;
import java.util.concurrent.Callable;
@@ -22,6 +22,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate5.SessionFactoryUtils;
import org.springframework.orm.hibernate5.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
@@ -37,22 +39,20 @@ import org.springframework.web.context.request.async.DeferredResultProcessingInt
* 2) The session is closed if an async request times out
*
* @author Rossen Stoyanchev
* @since 3.2.5
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
* @since 4.2
*/
@Deprecated
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter implements DeferredResultProcessingInterceptor {
private static final Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
private final SessionFactory sessionFactory;
private final org.springframework.orm.hibernate3.SessionHolder sessionHolder;
private final SessionHolder sessionHolder;
private volatile boolean timeoutInProgress;
public AsyncRequestInterceptor(SessionFactory sessionFactory, org.springframework.orm.hibernate3.SessionHolder sessionHolder) {
public AsyncRequestInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
this.sessionFactory = sessionFactory;
this.sessionHolder = sessionHolder;
}
@@ -87,7 +87,7 @@ class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter imple
private void closeAfterTimeout() {
if (this.timeoutInProgress) {
logger.debug("Closing Hibernate Session after async request timeout");
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5.support;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.support.DaoSupport;
import org.springframework.orm.hibernate5.HibernateTemplate;
/**
* Convenient super class for Hibernate-based data access objects.
*
* <p>Requires a {@link SessionFactory} to be set, providing a
* {@link org.springframework.orm.hibernate5.HibernateTemplate} based on it to
* subclasses through the {@link #getHibernateTemplate()} method.
* Can alternatively be initialized directly with a HibernateTemplate,
* in order to reuse the latter's settings such as the SessionFactory,
* exception translator, flush mode, etc.
*
* <p>This class will create its own HibernateTemplate instance if a SessionFactory
* is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
* by default. A custom HibernateTemplate instance can be used through overriding
* {@link #createHibernateTemplate}.
*
* <p><b>NOTE: Hibernate access code can also be coded in plain Hibernate style.
* Hence, for newly started projects, consider adopting the standard Hibernate
* style of coding data access objects instead, based on
* {@link SessionFactory#getCurrentSession()}.
* This HibernateTemplate primarily exists as a migration helper for Hibernate 3
* based data access code, to benefit from bug fixes in Hibernate 5.x.</b>
*
* @author Juergen Hoeller
* @since 4.2
* @see #setSessionFactory
* @see #getHibernateTemplate
* @see org.springframework.orm.hibernate5.HibernateTemplate
*/
public abstract class HibernateDaoSupport extends DaoSupport {
private HibernateTemplate hibernateTemplate;
/**
* Set the Hibernate SessionFactory to be used by this DAO.
* Will automatically create a HibernateTemplate for the given SessionFactory.
* @see #createHibernateTemplate
* @see #setHibernateTemplate
*/
public final void setSessionFactory(SessionFactory sessionFactory) {
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
}
}
/**
* Create a HibernateTemplate for the given SessionFactory.
* Only invoked if populating the DAO with a SessionFactory reference!
* <p>Can be overridden in subclasses to provide a HibernateTemplate instance
* with different configuration, or a custom HibernateTemplate subclass.
* @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
* @return the new HibernateTemplate instance
* @see #setSessionFactory
*/
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
return new HibernateTemplate(sessionFactory);
}
/**
* Return the Hibernate SessionFactory used by this DAO.
*/
public final SessionFactory getSessionFactory() {
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
}
/**
* Set the HibernateTemplate for this DAO explicitly,
* as an alternative to specifying a SessionFactory.
* @see #setSessionFactory
*/
public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
/**
* Return the HibernateTemplate for this DAO,
* pre-initialized with the SessionFactory or set explicitly.
* <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
* You may introspect its configuration, but not modify the configuration
* (other than from within an {@link #initDao} implementation).
* Consider creating a custom HibernateTemplate instance via
* {@code new HibernateTemplate(getSessionFactory())}, in which case
* you're allowed to customize the settings on the resulting instance.
*/
public final HibernateTemplate getHibernateTemplate() {
return this.hibernateTemplate;
}
@Override
protected final void checkDaoConfig() {
if (this.hibernateTemplate == null) {
throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
}
}
/**
* Conveniently obtain the current Hibernate Session.
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @see SessionFactory#getCurrentSession()
*/
protected final Session currentSession() throws DataAccessResourceFailureException {
return getSessionFactory().getCurrentSession();
}
}

View File

@@ -0,0 +1,222 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5.support;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate5.SessionFactoryUtils;
import org.springframework.orm.hibernate5.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Servlet Filter that binds a Hibernate Session to the thread for the entire
* processing of the request. Intended for the "Open Session in View" pattern,
* i.e. to allow for lazy loading in web views despite the original transactions
* already being completed.
*
* <p>This filter makes Hibernate Sessions available via the current thread, which
* will be autodetected by transaction managers. It is suitable for service layer
* transactions via {@link org.springframework.orm.hibernate5.HibernateTransactionManager}
* as well as for non-transactional execution (if configured appropriately).
*
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
* with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used
* in combination with service layer transactions that care for the flushing: The
* active transaction manager will temporarily change the flush mode to
* {@code FlushMode.AUTO} during a read-write transaction, with the flush
* mode reset to {@code FlushMode.NEVER} at the end of each transaction.
*
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
* have not appeared before, through the use of a single Hibernate Session for the
* processing of an entire request. In particular, the reassociation of persistent
* objects with a Hibernate Session has to occur at the very beginning of request
* processing, to avoid clashes with already loaded instances of the same objects.
*
* <p>Looks up the SessionFactory in Spring's root web application context.
* Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml};
* the default bean name is "sessionFactory".
*
* @author Juergen Hoeller
* @since 4.2
* @see #lookupSessionFactory
* @see OpenSessionInViewInterceptor
* @see OpenSessionInterceptor
* @see org.springframework.orm.hibernate5.HibernateTransactionManager
* @see TransactionSynchronizationManager
* @see SessionFactory#getCurrentSession()
*/
public class OpenSessionInViewFilter extends OncePerRequestFilter {
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
/**
* Set the bean name of the SessionFactory to fetch from Spring's
* root application context. Default is "sessionFactory".
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
*/
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
this.sessionFactoryBeanName = sessionFactoryBeanName;
}
/**
* Return the bean name of the SessionFactory to fetch from Spring's
* root application context.
*/
protected String getSessionFactoryBeanName() {
return this.sessionFactoryBeanName;
}
/**
* Returns "false" so that the filter may re-bind the opened Hibernate
* {@code Session} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
/**
* Returns "false" so that the filter may provide a Hibernate
* {@code Session} to each error dispatches.
*/
@Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
}
else {
boolean isFirstRequest = !isAsyncDispatch(request);
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
}
try {
filterChain.doFilter(request, response);
}
finally {
if (!participate) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (!isAsyncStarted(request)) {
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
}
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
* variant without arguments.
* @param request the current request
* @return the SessionFactory to use
*/
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
return lookupSessionFactory();
}
/**
* Look up the SessionFactory that this filter should use.
* <p>The default implementation looks for a bean with the specified name
* in Spring's root application context.
* @return the SessionFactory to use
* @see #getSessionFactoryBeanName
*/
protected SessionFactory lookupSessionFactory() {
if (logger.isDebugEnabled()) {
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
}
/**
* Open a Session for the SessionFactory that this filter uses.
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
* method and sets the {@link Session}'s flush mode to "MANUAL".
* @param sessionFactory the SessionFactory that this filter uses
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see FlushMode#MANUAL
*/
@SuppressWarnings("deprecation")
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
try {
Session session = sessionFactory.openSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate5.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate5.SessionFactoryUtils;
import org.springframework.orm.hibernate5.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
/**
* Spring web request interceptor that binds a Hibernate {@code Session} to the
* thread for the entire processing of the request.
*
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
* is a pattern that allows for the lazy loading of associations in web views despite
* the original transactions already being completed.
*
* <p>This interceptor makes Hibernate Sessions available via the current thread,
* which will be autodetected by transaction managers. It is suitable for service layer
* transactions via {@link org.springframework.orm.hibernate5.HibernateTransactionManager}
* as well as for non-transactional execution (if configured appropriately).
*
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is configured
* in a Spring application context and can thus take advantage of bean wiring.
*
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
* that have not appeared before, through the use of a single Hibernate
* {@code Session} for the processing of an entire request. In particular, the
* reassociation of persistent objects with a Hibernate {@code Session} has to
* occur at the very beginning of request processing, to avoid clashes with already
* loaded instances of the same objects.
*
* @author Juergen Hoeller
* @since 4.2
* @see OpenSessionInViewFilter
* @see OpenSessionInterceptor
* @see org.springframework.orm.hibernate5.HibernateTransactionManager
* @see TransactionSynchronizationManager
* @see SessionFactory#getCurrentSession()
*/
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
/**
* Suffix that gets appended to the {@code SessionFactory}
* {@code toString()} representation for the "participate in existing
* session handling" request attribute.
* @see #getParticipateAttributeName
*/
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
protected final Log logger = LogFactory.getLog(getClass());
private SessionFactory sessionFactory;
/**
* Set the Hibernate SessionFactory that should be used to create Hibernate Sessions.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Return the Hibernate SessionFactory that should be used to create Hibernate Sessions.
*/
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
/**
* Open a new Hibernate {@code Session} according and bind it to the thread via the
* {@link TransactionSynchronizationManager}.
*/
@Override
public void preHandle(WebRequest request) throws DataAccessException {
String participateAttributeName = getParticipateAttributeName();
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
if (asyncManager.hasConcurrentResult()) {
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
return;
}
}
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
// Do not modify the Session: just mark the request accordingly.
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
int newCount = (count != null ? count + 1 : 1);
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
}
else {
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
Session session = openSession();
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
AsyncRequestInterceptor asyncRequestInterceptor =
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
}
}
@Override
public void postHandle(WebRequest request, ModelMap model) {
}
/**
* Unbind the Hibernate {@code Session} from the thread and close it).
* @see TransactionSynchronizationManager
*/
@Override
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
if (!decrementParticipateCount(request)) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
private boolean decrementParticipateCount(WebRequest request) {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
if (count == null) {
return false;
}
// Do not modify the Session: just clear the marker.
if (count > 1) {
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
}
else {
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
}
return true;
}
@Override
public void afterConcurrentHandlingStarted(WebRequest request) {
if (!decrementParticipateCount(request)) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
}
/**
* Open a Session for the SessionFactory that this interceptor uses.
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
* method and sets the {@link Session}'s flush mode to "MANUAL".
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see FlushMode#MANUAL
*/
@SuppressWarnings("deprecation")
protected Session openSession() throws DataAccessResourceFailureException {
try {
Session session = getSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
/**
* Return the name of the request attribute that identifies that a request is
* already intercepted.
* <p>The default implementation takes the {@code toString()} representation
* of the {@code SessionFactory} instance and appends {@link #PARTICIPATE_SUFFIX}.
*/
protected String getParticipateAttributeName() {
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.orm.hibernate3.support;
package org.springframework.orm.hibernate5.support;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -25,6 +25,8 @@ import org.hibernate.SessionFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate5.SessionFactoryUtils;
import org.springframework.orm.hibernate5.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
@@ -36,20 +38,14 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* MVC setup. It opens a new {@link Session} with flush mode "MANUAL" since the
* Session is only meant for reading, except when participating in a transaction.
*
* <p>Note: This can serve as a streamlined alternative to the outdated
* {@link org.springframework.orm.hibernate3.HibernateInterceptor}, providing
* plain Session binding without any automatic exception translation or the like.
*
* @author Juergen Hoeller
* @since 4.0.2
* @since 4.2
* @see OpenSessionInViewInterceptor
* @see OpenSessionInViewFilter
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
* @see org.hibernate.SessionFactory#getCurrentSession()
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
* @see org.springframework.orm.hibernate5.HibernateTransactionManager
* @see TransactionSynchronizationManager
* @see SessionFactory#getCurrentSession()
*/
@Deprecated
public class OpenSessionInterceptor implements MethodInterceptor, InitializingBean {
private SessionFactory sessionFactory;
@@ -84,11 +80,11 @@ public class OpenSessionInterceptor implements MethodInterceptor, InitializingBe
// New Session to be bound for the current method's scope...
Session session = openSession();
try {
TransactionSynchronizationManager.bindResource(sf, new org.springframework.orm.hibernate3.SessionHolder(session));
TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
return invocation.proceed();
}
finally {
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(session);
SessionFactoryUtils.closeSession(session);
TransactionSynchronizationManager.unbindResource(sf);
}
}
@@ -104,8 +100,9 @@ public class OpenSessionInterceptor implements MethodInterceptor, InitializingBe
* method and sets the {@link Session}'s flush mode to "MANUAL".
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see org.hibernate.FlushMode#MANUAL
* @see FlushMode#MANUAL
*/
@SuppressWarnings("deprecation")
protected Session openSession() throws DataAccessResourceFailureException {
try {
Session session = getSessionFactory().openSession();

View File

@@ -0,0 +1,4 @@
/**
* Classes supporting the {@code org.springframework.orm.hibernate5} package.
*/
package org.springframework.orm.hibernate5.support;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockException;
import javax.persistence.Query;
import javax.persistence.QueryTimeoutException;
import javax.persistence.SynchronizationType;
import javax.persistence.TransactionRequiredException;
import org.apache.commons.logging.Log;
@@ -81,26 +82,6 @@ public abstract class EntityManagerFactoryUtils {
private static final Log logger = LogFactory.getLog(EntityManagerFactoryUtils.class);
private static Method createEntityManagerWithSynchronizationTypeMethod;
private static Object synchronizationTypeUnsynchronized;
static {
try {
@SuppressWarnings( "rawtypes" )
Class<Enum> synchronizationTypeClass = (Class<Enum>) ClassUtils.forName(
"javax.persistence.SynchronizationType", EntityManagerFactoryUtils.class.getClassLoader());
createEntityManagerWithSynchronizationTypeMethod = EntityManagerFactory.class.getMethod(
"createEntityManager", synchronizationTypeClass, Map.class);
synchronizationTypeUnsynchronized = Enum.valueOf(synchronizationTypeClass, "UNSYNCHRONIZED");
}
catch (Exception ex) {
// No JPA 2.1 API available
createEntityManagerWithSynchronizationTypeMethod = null;
}
}
/**
* Find an EntityManagerFactory with the given name in the given
* Spring application context (represented as ListableBeanFactory).
@@ -271,10 +252,9 @@ public abstract class EntityManagerFactoryUtils {
// Create a new EntityManager for use within the current transaction.
logger.debug("Opening JPA EntityManager");
EntityManager em = null;
if (!synchronizedWithTransaction && createEntityManagerWithSynchronizationTypeMethod != null) {
if (!synchronizedWithTransaction) {
try {
em = (EntityManager) ReflectionUtils.invokeMethod(createEntityManagerWithSynchronizationTypeMethod,
emf, synchronizationTypeUnsynchronized, properties);
em = emf.createEntityManager(SynchronizationType.UNSYNCHRONIZED, properties);
}
catch (AbstractMethodError err) {
// JPA 2.1 API available but method not actually implemented in persistence provider:

View File

@@ -115,11 +115,11 @@ public abstract class SharedEntityManagerCreator {
*/
public static EntityManager createSharedEntityManager(
EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction) {
Class<?> entityManagerInterface = (emf instanceof EntityManagerFactoryInfo ?
Class<?> emIfc = (emf instanceof EntityManagerFactoryInfo ?
((EntityManagerFactoryInfo) emf).getEntityManagerInterface() : EntityManager.class);
return createSharedEntityManager(emf, properties, synchronizedWithTransaction,
(entityManagerInterface == null ? NO_ENTITY_MANAGER_INTERFACES :
new Class<?>[] { entityManagerInterface }));
(emIfc == null ? NO_ENTITY_MANAGER_INTERFACES : new Class<?>[] {emIfc}));
}
/**

View File

@@ -17,7 +17,6 @@
package org.springframework.orm.jpa.persistenceunit;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
@@ -26,6 +25,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
@@ -73,8 +73,7 @@ import org.springframework.util.ResourceUtils;
* DataSource names are by default interpreted as JNDI names, and no load time weaving
* is available (which requires weaving to be turned off in the persistence provider).
*
* <p><b>NOTE: Spring's JPA support requires JPA 2.0 or higher, as of Spring 4.0.</b>
* Spring's persistence unit bootstrapping automatically detects JPA 2.1 at runtime.
* <p><b>NOTE: Spring's JPA support requires JPA 2.1 or higher, as of Spring 5.0.</b>
*
* @author Juergen Hoeller
* @since 2.0
@@ -116,15 +115,7 @@ public class DefaultPersistenceUnitManager
entityTypeFilters.add(new AnnotationTypeFilter(Entity.class, false));
entityTypeFilters.add(new AnnotationTypeFilter(Embeddable.class, false));
entityTypeFilters.add(new AnnotationTypeFilter(MappedSuperclass.class, false));
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>)
ClassUtils.forName("javax.persistence.Converter", DefaultPersistenceUnitManager.class.getClassLoader());
entityTypeFilters.add(new AnnotationTypeFilter(converterAnnotation, false));
}
catch (ClassNotFoundException ex) {
// JPA 2.1 API not available
}
entityTypeFilters.add(new AnnotationTypeFilter(Converter.class, false));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.PersistenceProperty;
import javax.persistence.PersistenceUnit;
import javax.persistence.SynchronizationType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
@@ -168,11 +169,6 @@ public class PersistenceAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable {
/* Check JPA 2.1 PersistenceContext.synchronization() attribute */
private static final Method synchronizationAttribute =
ClassUtils.getMethodIfAvailable(PersistenceContext.class, "synchronization");
private Object jndiEnvironment;
private boolean resourceRef = true;
@@ -662,8 +658,7 @@ public class PersistenceAnnotationBeanPostProcessor
}
this.unitName = pc.unitName();
this.type = pc.type();
this.synchronizedWithTransaction = (synchronizationAttribute == null ||
"SYNCHRONIZED".equals(ReflectionUtils.invokeMethod(synchronizationAttribute, pc).toString()));
this.synchronizedWithTransaction = SynchronizationType.SYNCHRONIZED.equals(pc.synchronization());
this.properties = properties;
}
else {

View File

@@ -28,7 +28,6 @@ import org.hibernate.HibernateException;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.OptimisticLockException;
import org.hibernate.PersistentObjectException;
import org.hibernate.PessimisticLockException;
import org.hibernate.PropertyValueException;
@@ -40,6 +39,8 @@ import org.hibernate.StaleStateException;
import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.hibernate.dialect.lock.PessimisticEntityLockException;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.DataException;
import org.hibernate.exception.JDBCConnectionException;
@@ -57,7 +58,6 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.jpa.DefaultJpaDialect;
@@ -67,13 +67,11 @@ import org.springframework.transaction.InvalidIsolationLevelException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* {@link org.springframework.orm.jpa.JpaDialect} implementation for
* Hibernate EntityManager. Developed and tested against Hibernate 3.6,
* 4.2/4.3 as well as 5.0/5.1/5.2.
* Hibernate EntityManager. Developed against Hibernate 5.0/5.1/5.2.
*
* @author Juergen Hoeller
* @author Costin Leau
@@ -85,29 +83,9 @@ import org.springframework.util.ReflectionUtils;
@SuppressWarnings("serial")
public class HibernateJpaDialect extends DefaultJpaDialect {
private static Class<?> optimisticLockExceptionClass;
private static Class<?> pessimisticLockExceptionClass;
private static Method getFlushMode;
static {
// Checking for Hibernate 4.x's Optimistic/PessimisticEntityLockException
ClassLoader cl = HibernateJpaDialect.class.getClassLoader();
try {
optimisticLockExceptionClass = cl.loadClass("org.hibernate.dialect.lock.OptimisticEntityLockException");
}
catch (ClassNotFoundException ex) {
// OptimisticLockException is deprecated on Hibernate 4.x; we're just using it on 3.x anyway
optimisticLockExceptionClass = OptimisticLockException.class;
}
try {
pessimisticLockExceptionClass = cl.loadClass("org.hibernate.dialect.lock.PessimisticEntityLockException");
}
catch (ClassNotFoundException ex) {
pessimisticLockExceptionClass = null;
}
try {
// Hibernate 5.2+ getHibernateFlushMode()
getFlushMode = Session.class.getMethod("getHibernateFlushMode");
@@ -126,7 +104,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
}
boolean prepareConnection = (HibernateConnectionHandle.sessionConnectionMethod == null);
boolean prepareConnection = true;
/**
@@ -135,9 +113,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
* isolation level and/or the transaction's read-only flag to the underlying
* JDBC Connection.
* <p>Default is "true" on Hibernate EntityManager 4.x (with its 'on-close'
* connection release mode, and "false" on Hibernate EntityManager 3.6 (due to
* the 'after-transaction' release mode there). <b>Note that Hibernate 4.2+ is
* strongly recommended in order to make isolation levels work efficiently.</b>
* connection release mode.
* <p>If you turn this flag off, JPA transaction management will not support
* per-transaction isolation levels anymore. It will not call
* {@code Connection.setReadOnly(true)} for read-only transactions anymore either.
@@ -179,9 +155,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
}
else if (isolationLevelNeeded) {
throw new InvalidIsolationLevelException(getClass().getSimpleName() +
" does not support custom isolation levels since the 'prepareConnection' flag is off. " +
"This is the case on Hibernate 3.6 by default; either switch that flag at your own risk " +
"or upgrade to Hibernate 4.x, with 4.2+ recommended.");
" does not support custom isolation levels since the 'prepareConnection' flag is off.");
}
}
@@ -319,10 +293,10 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
if (ex instanceof StaleStateException) {
return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex);
}
if (optimisticLockExceptionClass.isInstance(ex)) {
if (ex instanceof OptimisticEntityLockException) {
return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex);
}
if (pessimisticLockExceptionClass != null && pessimisticLockExceptionClass.isInstance(ex)) {
if (ex instanceof PessimisticEntityLockException) {
if (ex.getCause() instanceof LockAcquisitionException) {
return new CannotAcquireLockException(ex.getMessage(), ex.getCause());
}
@@ -376,11 +350,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
private static class HibernateConnectionHandle implements ConnectionHandle {
// This will find a corresponding method on Hibernate 3.x but not on 4.x
private static final Method sessionConnectionMethod =
ClassUtils.getMethodIfAvailable(Session.class, "connection");
private static volatile Method connectionMethodToUse = sessionConnectionMethod;
private static volatile Method connectionMethodToUse;
private final Session session;
@@ -395,20 +365,12 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
@Override
public void releaseConnection(Connection con) {
if (sessionConnectionMethod != null) {
// Need to explicitly call close() with Hibernate 3.x in order to allow
// for eager release of the underlying physical Connection if necessary.
// However, do not do this on Hibernate 4.2+ since it would return the
// physical Connection to the pool right away, making it unusable for
// further operations within the current transaction!
JdbcUtils.closeConnection(con);
}
}
public static Connection doGetConnection(Session session) {
try {
if (connectionMethodToUse == null) {
// Reflective lookup to find SessionImpl's connection() method on Hibernate 4.x
// Reflective lookup to find SessionImpl's connection() method on Hibernate 4.x/5.x
connectionMethodToUse = session.getClass().getMethod("connection");
}
return (Connection) ReflectionUtils.invokeMethod(connectionMethodToUse, session);

View File

@@ -32,11 +32,13 @@ import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle9iDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.jpa.HibernateEntityManager;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate
* EntityManager. Developed and tested against Hibernate 3.6, 4.2/4.3 as well as 5.x.
* <b>Hibernate 4.2+ is strongly recommended for use with Spring 4.0+.</b>
* EntityManager. Developed and tested against Hibernate 5.0, 5.1 and 5.2;
* backwards-compatible with Hibernate 4.3 as well.
*
* <p>Exposes Hibernate's persistence provider and EntityManager extension interface,
* and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings.
@@ -46,18 +48,10 @@ import org.hibernate.dialect.SQLServerDialect;
* along with Spring-driven entity scanning which requires no {@code persistence.xml}
* ({@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan}).
*
* <p>Note that the package location of Hibernate's JPA support changed from 4.2 to 4.3:
* from {@code org.hibernate.ejb.HibernateEntityManager(Factory)} to
* {@code org.hibernate.jpa.HibernateEntityManager(Factory)}. As of Spring 4.0,
* we're exposing the correct, non-deprecated variant depending on the Hibernate
* version encountered at runtime, in order to avoid deprecation log entries.
*
* @author Juergen Hoeller
* @author Rod Johnson
* @since 2.0
* @see HibernateJpaDialect
* @see org.hibernate.ejb.HibernatePersistence
* @see org.hibernate.ejb.HibernateEntityManager
*/
public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
@@ -73,31 +67,9 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
@SuppressWarnings("unchecked")
public HibernateJpaVendorAdapter() {
ClassLoader cl = HibernateJpaVendorAdapter.class.getClassLoader();
Class<? extends EntityManagerFactory> emfIfcToUse;
Class<? extends EntityManager> emIfcToUse;
Class<?> providerClass;
PersistenceProvider providerToUse;
try {
try {
// Try Hibernate 4.3/5.0's org.hibernate.jpa package in order to avoid deprecation warnings
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.jpa.HibernateEntityManagerFactory");
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.jpa.HibernateEntityManager");
providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider");
}
catch (ClassNotFoundException ex) {
// Fall back to Hibernate 3.6-4.2 org.hibernate.ejb package
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.ejb.HibernateEntityManagerFactory");
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.ejb.HibernateEntityManager");
providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateEjbPersistenceProvider");
}
providerToUse = (PersistenceProvider) providerClass.newInstance();
}
catch (Exception ex) {
throw new IllegalStateException("Failed to determine Hibernate PersistenceProvider", ex);
}
this.persistenceProvider = providerToUse;
this.entityManagerFactoryInterface = emfIfcToUse;
this.entityManagerInterface = emIfcToUse;
this.persistenceProvider = new SpringHibernateJpaPersistenceProvider();
this.entityManagerFactoryInterface = HibernateEntityManagerFactory.class;
this.entityManagerInterface = HibernateEntityManager.class;
}
@@ -170,15 +142,15 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
protected Class<?> determineDatabaseDialectClass(Database database) {
switch (database) {
case DB2: return DB2Dialect.class;
case DERBY: return DerbyDialect.class; // DerbyDialect deprecated in 4.x
case DERBY: return DerbyDialect.class;
case H2: return H2Dialect.class;
case HSQL: return HSQLDialect.class;
case INFORMIX: return InformixDialect.class;
case MYSQL: return MySQLDialect.class;
case ORACLE: return Oracle9iDialect.class;
case POSTGRESQL: return PostgreSQLDialect.class; // PostgreSQLDialect deprecated in 4.x
case POSTGRESQL: return PostgreSQLDialect.class;
case SQL_SERVER: return SQLServerDialect.class;
case SYBASE: return org.hibernate.dialect.SybaseDialect.class; // SybaseDialect deprecated in 3.6 but not 4.x
case SYBASE: return org.hibernate.dialect.SybaseDialect.class;
default: return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,39 +16,45 @@
package org.springframework.orm.jpa.vendor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceUnitInfo;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.ejb.HibernatePersistence;
import org.hibernate.cfg.Configuration;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
/**
* Spring-specific subclass of the standard {@link HibernatePersistence}
* provider from the {@code org.hibernate.ejb} package, adding support for
* Spring-specific subclass of the standard {@link HibernatePersistenceProvider}
* from the {@code org.hibernate.jpa} package, adding support for
* {@link SmartPersistenceUnitInfo#getManagedPackages()}.
*
* <p>Compatible with Hibernate 3.6 as well as 4.0-4.2.
*
* @author Juergen Hoeller
* @author Joris Kuipers
* @since 4.1
* @see Ejb3Configuration#addPackage
* @see Configuration#addPackage
*/
class SpringHibernateEjbPersistenceProvider extends HibernatePersistence {
class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider {
@Override
@SuppressWarnings("rawtypes")
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) {
Ejb3Configuration cfg = new Ejb3Configuration();
final List<String> mergedClassesAndPackages = new ArrayList<String>(info.getManagedClassNames());
if (info instanceof SmartPersistenceUnitInfo) {
for (String managedPackage : ((SmartPersistenceUnitInfo) info).getManagedPackages()) {
cfg.addPackage(managedPackage);
}
mergedClassesAndPackages.addAll(((SmartPersistenceUnitInfo) info).getManagedPackages());
}
Ejb3Configuration configured = cfg.configure(info, properties);
return (configured != null ? configured.buildEntityManagerFactory() : null);
return new EntityManagerFactoryBuilderImpl(
new PersistenceUnitInfoDescriptor(info) {
@Override
public List<String> getManagedClassNames() {
return mergedClassesAndPackages;
}
}, properties).build();
}
}