diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/ConfigurableJtaPlatform.java b/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/ConfigurableJtaPlatform.java index 85ca2d4c16b..ecc4b8352b6 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/ConfigurableJtaPlatform.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/ConfigurableJtaPlatform.java @@ -31,14 +31,14 @@ import org.springframework.transaction.jta.UserTransactionAdapter; import org.springframework.util.Assert; /** - * Implementation of Hibernate 5's JtaPlatform SPI, exposing passed-in {@link TransactionManager}, + * Implementation of Hibernate's JtaPlatform SPI, exposing passed-in {@link TransactionManager}, * {@link UserTransaction} and {@link TransactionSynchronizationRegistry} references. * * @author Juergen Hoeller - * @since 7.0 + * @since 7.0.4 */ @SuppressWarnings("serial") -class ConfigurableJtaPlatform implements JtaPlatform { +public class ConfigurableJtaPlatform implements JtaPlatform { private final TransactionManager transactionManager; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java b/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java index 9072dc31738..80f69e02c85 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/LocalSessionFactoryBuilder.java @@ -180,32 +180,25 @@ public class LocalSessionFactoryBuilder extends Configuration { /** * 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 + * manager for Hibernate's session and cache synchronization, with the * "hibernate.transaction.jta.platform" automatically set to it. *
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. + * {@link TransactionManager} reference to be usable here. *
Note: If this is set, the Hibernate settings should not contain a JTA platform * setting to avoid meaningless double configuration. + * @see AvailableSettings#JTA_PLATFORM */ public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) { Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null"); if (jtaTransactionManager instanceof JtaTransactionManager springJtaTm) { - 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 { - if (springJtaTm.getTransactionManager() == null) { - throw new IllegalArgumentException( - "Can only apply JtaTransactionManager which has a TransactionManager reference set"); - } - getProperties().put(AvailableSettings.JTA_PLATFORM, - new ConfigurableJtaPlatform(springJtaTm.getTransactionManager(), springJtaTm.getUserTransaction(), - springJtaTm.getTransactionSynchronizationRegistry())); + if (springJtaTm.getTransactionManager() == null) { + throw new IllegalArgumentException( + "Can only apply JtaTransactionManager which has a TransactionManager reference set"); } + getProperties().put(AvailableSettings.JTA_PLATFORM, + new ConfigurableJtaPlatform(springJtaTm.getTransactionManager(), springJtaTm.getUserTransaction(), + springJtaTm.getTransactionSynchronizationRegistry())); } else if (jtaTransactionManager instanceof TransactionManager jtaTm) { getProperties().put(AvailableSettings.JTA_PLATFORM, diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java index fac97fb201d..6e051d62ca3 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java @@ -23,6 +23,7 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.spi.PersistenceProvider; import jakarta.persistence.spi.PersistenceUnitInfo; +import jakarta.transaction.TransactionManager; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AvailableSettings; @@ -38,7 +39,13 @@ import org.hibernate.dialect.SybaseDialect; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.jspecify.annotations.Nullable; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.orm.jpa.hibernate.ConfigurableJtaPlatform; +import org.springframework.orm.jpa.hibernate.SpringBeanContainer; import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo; +import org.springframework.transaction.jta.JtaTransactionManager; /** * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate. @@ -65,7 +72,7 @@ import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo; * @since 2.0 * @see HibernateJpaDialect */ -public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { +public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter implements BeanFactoryAware { private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect(); @@ -75,6 +82,10 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { private final Class extends EntityManager> entityManagerInterface; + private @Nullable Object jtaTransactionManager; + + private @Nullable BeanFactory beanFactory; + public HibernateJpaVendorAdapter() { this.persistenceProvider = new SpringHibernateJpaPersistenceProvider(); @@ -110,6 +121,29 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { this.jpaDialect.setPrepareConnection(prepareConnection); } + /** + * Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager} + * or the JTA {@link jakarta.transaction.TransactionManager} to be used with Hibernate, + * if any. Implicitly sets up {@code JtaPlatform}. + * @since 7.0.4 + * @see AvailableSettings#JTA_PLATFORM + */ + public void setJtaTransactionManager(Object jtaTransactionManager) { + this.jtaTransactionManager = jtaTransactionManager; + } + + /** + * Set the Spring {@link ConfigurableListableBeanFactory} to use for a default + * Hibernate setup with {@link SpringBeanContainer}. This enables autowiring of + * Hibernate attribute converters and entity listeners. + * @since 7.0.4 + * @see AvailableSettings#BEAN_CONTAINER + */ + @Override + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + @Override public PersistenceProvider getPersistenceProvider() { @@ -163,7 +197,31 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_HOLD); } - // For SpringBeanContainer to be called on Hibernate 6.2 + // Derive Hibernate JtaPlatform from Spring (Jta)TransactionManager setup. + if (this.jtaTransactionManager != null) { + if (this.jtaTransactionManager instanceof JtaTransactionManager springJtaTm) { + if (springJtaTm.getTransactionManager() == null) { + throw new IllegalArgumentException( + "Can only apply JtaTransactionManager which has a TransactionManager reference set"); + } + jpaProperties.put(AvailableSettings.JTA_PLATFORM, new ConfigurableJtaPlatform( + springJtaTm.getTransactionManager(), springJtaTm.getUserTransaction(), + springJtaTm.getTransactionSynchronizationRegistry())); + } + else if (this.jtaTransactionManager instanceof TransactionManager jtaTm) { + jpaProperties.put(AvailableSettings.JTA_PLATFORM, new ConfigurableJtaPlatform(jtaTm, null, null)); + } + else { + throw new IllegalArgumentException( + "Unknown transaction manager type: " + this.jtaTransactionManager.getClass().getName()); + } + } + + // This enables autowiring of Hibernate attribute converters and entity listeners. + if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) { + jpaProperties.put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(clbf)); + } + // For SpringBeanContainer to actually be called at runtime. jpaProperties.put("hibernate.cdi.extensions", "true"); return jpaProperties;