HibernateTransactionManager for Hibernate 4 supports "entityInterceptor(BeanName)" property
Issue: SPR-10301
This commit is contained in:
@@ -22,12 +22,16 @@ import javax.sql.DataSource;
|
|||||||
import org.hibernate.ConnectionReleaseMode;
|
import org.hibernate.ConnectionReleaseMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.Interceptor;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.engine.transaction.spi.TransactionContext;
|
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||||
|
|
||||||
|
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.beans.factory.InitializingBean;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
import org.springframework.dao.DataAccessResourceFailureException;
|
||||||
@@ -100,7 +104,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
||||||
implements ResourceTransactionManager, InitializingBean {
|
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
private SessionFactory sessionFactory;
|
||||||
|
|
||||||
@@ -112,6 +116,14 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||||||
|
|
||||||
private boolean hibernateManagedSession = false;
|
private boolean hibernateManagedSession = false;
|
||||||
|
|
||||||
|
private Object entityInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just needed for entityInterceptorBeanName.
|
||||||
|
* @see #setEntityInterceptorBeanName
|
||||||
|
*/
|
||||||
|
private BeanFactory beanFactory;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new HibernateTransactionManager instance.
|
* Create a new HibernateTransactionManager instance.
|
||||||
@@ -229,7 +241,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||||||
* to always return a proper Session when called for a Spring-managed transaction;
|
* to always return a proper Session when called for a Spring-managed transaction;
|
||||||
* transaction begin will fail if the {@code getCurrentSession()} call fails.
|
* transaction begin will fail if the {@code getCurrentSession()} call fails.
|
||||||
* <p>This mode will typically be used in combination with a custom Hibernate
|
* <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.
|
* Sessions in a place other than Spring's TransactionSynchronizationManager.
|
||||||
* It may also be used in combination with Spring's Open-Session-in-View support
|
* 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
|
* (using Spring's default {@link SpringSessionContext}), in which case it subtly
|
||||||
@@ -242,10 +254,81 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||||||
this.hibernateManagedSession = hibernateManagedSession;
|
this.hibernateManagedSession = hibernateManagedSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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.
|
||||||
|
* @see LocalSessionFactoryBean#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 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 Interceptor) {
|
||||||
|
return (Interceptor) entityInterceptor;
|
||||||
|
}
|
||||||
|
else if (this.entityInterceptor instanceof String) {
|
||||||
|
if (this.beanFactory == null) {
|
||||||
|
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
|
||||||
|
}
|
||||||
|
String beanName = (String) this.entityInterceptor;
|
||||||
|
return this.beanFactory.getBean(beanName, Interceptor.class);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
if (getSessionFactory() == null) {
|
if (getSessionFactory() == null) {
|
||||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
||||||
}
|
}
|
||||||
|
if (this.entityInterceptor instanceof String && this.beanFactory == null) {
|
||||||
|
throw new IllegalArgumentException("Property 'beanFactory' is required for 'entityInterceptorBeanName'");
|
||||||
|
}
|
||||||
|
|
||||||
// Check for SessionFactory's DataSource.
|
// Check for SessionFactory's DataSource.
|
||||||
if (this.autodetectDataSource && getDataSource() == null) {
|
if (this.autodetectDataSource && getDataSource() == null) {
|
||||||
@@ -325,7 +408,10 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
|
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
|
||||||
Session newSession = getSessionFactory().openSession();
|
Interceptor entityInterceptor = getEntityInterceptor();
|
||||||
|
Session newSession = (entityInterceptor != null ?
|
||||||
|
getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
|
||||||
|
getSessionFactory().openSession());
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
|
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user