diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java index 6c6cfe009ae..fc167cf5016 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java @@ -74,6 +74,14 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { "org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", "org.hibernate.service.jta.platform.internal.NoJtaPlatform" }; + /** + * {@code WebSphereExtendedJtaPlatform} implementations for various Hibernate + * versions. + */ + private static final String WEBSHERE_JTA_PLATFORM_CLASSES[] = { + "org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform", + "org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform", }; + @Autowired private JpaProperties properties; @@ -104,25 +112,14 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { throws LinkageError { JtaTransactionManager jtaTransactionManager = getJtaTransactionManager(); if (jtaTransactionManager != null) { - try { - vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform( - jtaTransactionManager)); + if (runningOnWebSphere()) { + // We can never use SpringJtaPlatform on WebSphere as + // WebSphereUowTransactionManger has a null TransactionManager + // which will cause Hibernate to NPE + configureWebSphereTransactionPlatform(vendorProperties); } - catch (NoClassDefFoundError ex) { - // Can happen if Hibernate 4.2 is used (for example on WAS) - if (isUsingJndi()) { - // Assume that we are not using a stand-alone transaction manager - // and Hibernate will use JNDI - if (logger.isDebugEnabled()) { - logger.debug("Unable to set Hibernate JTA platform : " - + ex.getMessage()); - } - } - else { - throw new IllegalStateException("Unable to set Hibernate JTA " - + "platform, are you using the correct " - + "version of hibernate?", ex); - } + else { + configureSpringJtaPlatform(vendorProperties, jtaTransactionManager); } } else { @@ -130,6 +127,56 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { } } + private boolean runningOnWebSphere() { + return ClassUtils.isPresent( + "com.ibm.websphere.jtaextensions.ExtendedJTATransaction", getClass() + .getClassLoader()); + } + + private void configureWebSphereTransactionPlatform( + Map vendorProperties) { + vendorProperties.put(JTA_PLATFORM, getWebSphereJtaPlatformManager()); + } + + private Object getWebSphereJtaPlatformManager() { + return getJtaPlatformManager(WEBSHERE_JTA_PLATFORM_CLASSES); + } + + private Object getJtaPlatformManager(String[] candidates) { + for (String candidate : candidates) { + try { + return Class.forName(candidate).newInstance(); + } + catch (Exception ex) { + // Continue searching + } + } + throw new IllegalStateException("Could not configure JTA platform"); + } + + private void configureSpringJtaPlatform(Map vendorProperties, + JtaTransactionManager jtaTransactionManager) { + try { + vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform( + jtaTransactionManager)); + } + catch (NoClassDefFoundError ex) { + // Can happen if Hibernate 4.2 is used + if (isUsingJndi()) { + // Assume that Hibernate will use JNDI + if (logger.isDebugEnabled()) { + logger.debug("Unable to set Hibernate JTA platform : " + + ex.getMessage()); + } + } + else { + throw new IllegalStateException("Unable to set Hibernate JTA " + + "platform, are you using the correct " + + "version of Hibernate?", ex); + } + } + } + private boolean isUsingJndi() { try { return JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable(); @@ -140,15 +187,7 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { } private Object getNoJtaPlatformManager() { - for (String noJtaPlatformClass : NO_JTA_PLATFORM_CLASSES) { - try { - return Class.forName(noJtaPlatformClass).newInstance(); - } - catch (Exception ex) { - // Continue searching - } - } - throw new IllegalStateException("Could not configure JTA platform"); + return getJtaPlatformManager(NO_JTA_PLATFORM_CLASSES); } @Order(Ordered.HIGHEST_PRECEDENCE + 20) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index 16a290c7f02..c0a1cb15118 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -32,11 +32,13 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration; import org.springframework.boot.autoconfigure.jta.JtaProperties; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; +import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -148,6 +150,17 @@ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigura this.context.refresh(); } + @Test + public void defaultJtaPlatform() throws Exception { + this.context.register(JtaProperties.class, JtaAutoConfiguration.class); + setupTestConfiguration(); + this.context.refresh(); + Map jpaPropertyMap = this.context.getBean( + LocalContainerEntityManagerFactoryBean.class).getJpaPropertyMap(); + assertThat(jpaPropertyMap.get("hibernate.transaction.jta.platform"), + instanceOf(SpringJtaPlatform.class)); + } + @Test public void testCustomJtaPlatform() throws Exception { EnvironmentTestUtils.addEnvironment(this.context,