From 7ec444444f9ff02eabb29ff0268a59f3cff08d9e Mon Sep 17 00:00:00 2001 From: Alexandru-Constantin Bledea Date: Fri, 10 Nov 2017 08:42:17 +0200 Subject: [PATCH] SPR-16162 make JpaVendorAdapter configuration properties more transaction type aware --- .../jpa/AbstractEntityManagerFactoryBean.java | 28 +++++++++++++++---- .../orm/jpa/JpaVendorAdapter.java | 15 ++++++++++ ...ocalContainerEntityManagerFactoryBean.java | 15 ++++++++-- .../jpa/vendor/AbstractJpaVendorAdapter.java | 7 +++++ .../jpa/vendor/HibernateJpaVendorAdapter.java | 12 ++++++-- 5 files changed, 68 insertions(+), 9 deletions(-) diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java index c92f3a28429b..15a8f42a4d23 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java @@ -38,6 +38,7 @@ import javax.persistence.Query; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; import org.apache.commons.logging.Log; @@ -336,18 +337,20 @@ public void setBeanName(String name) { @Override public final void afterPropertiesSet() throws PersistenceException { + beforeAfterPropertiesSet(); if (this.jpaVendorAdapter != null) { if (this.persistenceProvider == null) { this.persistenceProvider = this.jpaVendorAdapter.getPersistenceProvider(); } Map vendorPropertyMap = this.jpaVendorAdapter.getJpaPropertyMap(); if (vendorPropertyMap != null) { - vendorPropertyMap.forEach((key, value) -> { - if (!this.jpaPropertyMap.containsKey(key)) { - this.jpaPropertyMap.put(key, value); - } - }); + vendorPropertyMap.forEach(this::addJpaPropertyIfNotExists); } + + PersistenceUnitTransactionType transactionType = determineTransactionType(); + jpaVendorAdapter.getAdditionalJpaPropertyMapByTransactionType(transactionType) + .forEach(this::addJpaPropertyIfNotExists); + if (this.entityManagerFactoryInterface == null) { this.entityManagerFactoryInterface = this.jpaVendorAdapter.getEntityManagerFactoryInterface(); if (!ClassUtils.isVisible(this.entityManagerFactoryInterface, this.beanClassLoader)) { @@ -380,6 +383,21 @@ public final void afterPropertiesSet() throws PersistenceException { this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory); } + @Nullable + protected PersistenceUnitTransactionType determineTransactionType() { + return null; + } + + private void addJpaPropertyIfNotExists(String key, Object value) { + if (!this.jpaPropertyMap.containsKey(key)) { + this.jpaPropertyMap.put(key, value); + } + } + + protected void beforeAfterPropertiesSet() { + // Allow subclasses to basically call afterPropertiesSet as well before this class + } + private EntityManagerFactory buildNativeEntityManagerFactory() { EntityManagerFactory emf = createNativeEntityManagerFactory(); if (this.jpaVendorAdapter != null) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaVendorAdapter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaVendorAdapter.java index 6809c9074645..09d32656e032 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaVendorAdapter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaVendorAdapter.java @@ -21,6 +21,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitTransactionType; import org.springframework.lang.Nullable; @@ -65,6 +66,20 @@ public interface JpaVendorAdapter { @Nullable Map getJpaPropertyMap(); + /** + * Return a Map of vendor-specific JPA properties based on the transaction type, + * typically based on settings in this JpaVendorAdapter instance. + *

Note that there might be further JPA properties defined on + * the EntityManagerFactory bean, which might potentially override + * individual JPA property values specified here. + * @param transactionType the transaction type if can determine it or null if we can't + * @return a Map of JPA properties, as accepted by the standard + * JPA bootstrap facilities, or an empty Map if there are no such properties to expose + * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map) + * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map) + */ + Map getAdditionalJpaPropertyMapByTransactionType(@Nullable PersistenceUnitTransactionType transactionType); + /** * Return the vendor-specific JpaDialect implementation for this * provider, or {@code null} if there is none. diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java index 9483e73eb9bc..e4240fc489d2 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java @@ -22,6 +22,7 @@ import javax.persistence.ValidationMode; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; import org.springframework.beans.BeanUtils; @@ -320,9 +321,8 @@ public void setResourceLoader(ResourceLoader resourceLoader) { this.internalPersistenceUnitManager.setResourceLoader(resourceLoader); } - @Override - protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException { + protected void beforeAfterPropertiesSet() { PersistenceUnitManager managerToUse = this.persistenceUnitManager; if (this.persistenceUnitManager == null) { this.internalPersistenceUnitManager.afterPropertiesSet(); @@ -330,6 +330,10 @@ protected EntityManagerFactory createNativeEntityManagerFactory() throws Persist } this.persistenceUnitInfo = determinePersistenceUnitInfo(managerToUse); + } + + @Override + protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException { JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter(); if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof SmartPersistenceUnitInfo) { String rootPackage = jpaVendorAdapter.getPersistenceProviderRootPackage(); @@ -392,6 +396,13 @@ protected PersistenceUnitInfo determinePersistenceUnitInfo(PersistenceUnitManage protected void postProcessEntityManagerFactory(EntityManagerFactory emf, PersistenceUnitInfo pui) { } + @Override + protected PersistenceUnitTransactionType determineTransactionType() { + if (this.persistenceUnitInfo != null) { + return this.persistenceUnitInfo.getTransactionType(); + } + return super.determineTransactionType(); + } @Override @Nullable diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java index 269d205cf54f..12a41bcf54ac 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java @@ -16,9 +16,11 @@ package org.springframework.orm.jpa.vendor; +import java.util.Collections; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; +import javax.persistence.spi.PersistenceUnitTransactionType; import org.springframework.lang.Nullable; import org.springframework.orm.jpa.JpaDialect; @@ -129,6 +131,11 @@ public String getPersistenceProviderRootPackage() { return null; } + @Override + public Map getAdditionalJpaPropertyMapByTransactionType(@Nullable PersistenceUnitTransactionType transactionType) { + return Collections.emptyMap(); + } + @Override @Nullable public JpaDialect getJpaDialect() { 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 cd2e5f750e8e..7f357f42d290 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 @@ -21,6 +21,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitTransactionType; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.DB2Dialect; @@ -36,6 +37,8 @@ import org.springframework.lang.Nullable; +import static javax.persistence.spi.PersistenceUnitTransactionType.JTA; + /** * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate * EntityManager. Developed and tested against Hibernate 5.0, 5.1 and 5.2; @@ -130,7 +133,13 @@ public Map getJpaPropertyMap() { jpaProperties.put(AvailableSettings.SHOW_SQL, "true"); } - if (this.jpaDialect.prepareConnection) { + return jpaProperties; + } + + @Override + public Map getAdditionalJpaPropertyMapByTransactionType(@Nullable PersistenceUnitTransactionType transactionType) { + Map jpaProperties = new HashMap<>(); + if (this.jpaDialect.prepareConnection && transactionType != JTA) { // Hibernate 5.1/5.2: manually enforce connection release mode ON_CLOSE (the former default) try { // Try Hibernate 5.2 @@ -148,7 +157,6 @@ public Map getJpaPropertyMap() { } } } - return jpaProperties; }