From 6f9f335ea1ca03665a7c7f81649a931e93a6b902 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 12 Sep 2014 14:19:10 -0500 Subject: [PATCH] Add additional class conditions for JTA auto-configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, JTA auto-configuration would fail with a variety of ClassNotFoundExceptions and NoClassDefFoundErrors if it was used with an “incomplete” classpath. This commit adds a number of classes to @ConditionalOnClass annotations so that the auto-configuration backs off gracefully in the absence of certain classes. Specifically, the following now work as expected: - Deploying an app to a server with JTA available via JNDI when the app does not use transactions - Auto-configuration of Atomikos without JMS - Auto-configuration of Bitronix without JMS Both XADataSourceAutoConfiguration and JndiDataSourceAutoConfiguration have been updated to back off in the absence of spring-jdbc; a dependency of DataSourceProperties which is used by both classes. Error handling in AtomikosDependsOnBeanFactoryPostProcessor and BitronixDependentBeanFactoryPostProcessor has been enhanced so that the correct dependencies are established, even in the absence of JMS. Fixes gh-1538 --- .../jdbc/JndiDataSourceAutoConfiguration.java | 5 +++-- .../jdbc/XADataSourceAutoConfiguration.java | 4 +++- .../jta/AtomikosJtaConfiguration.java | 21 ++++++++++++------- .../jta/BitronixJtaConfiguration.java | 18 +++++++++------- .../jta/JndiJtaConfiguration.java | 4 +++- .../jta/JtaAutoConfigurationTests.java | 2 +- ...ikosDependsOnBeanFactoryPostProcessor.java | 3 +++ ...onixDependentBeanFactoryPostProcessor.java | 3 +++ 8 files changed, 41 insertions(+), 19 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java index 2308938aea..b033bde80d 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; /** @@ -38,7 +39,7 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; @Configuration @AutoConfigureBefore({ XADataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class }) -@ConditionalOnClass(DataSource.class) +@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @ConditionalOnProperty(prefix = DataSourceProperties.PREFIX, name = "jndi-name") @EnableConfigurationProperties(DataSourceProperties.class) public class JndiDataSourceAutoConfiguration { @@ -50,4 +51,4 @@ public class JndiDataSourceAutoConfiguration { return dataSourceLookup.getDataSource(properties.getJndiName()); } -} +} \ No newline at end of file diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfiguration.java index 1f5c00b844..53864bb051 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfiguration.java @@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jta.XADataSourceWrapper; import org.springframework.context.annotation.Bean; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -50,7 +51,8 @@ import org.springframework.util.StringUtils; @AutoConfigureBefore(DataSourceAutoConfiguration.class) @AutoConfigureAfter(JtaAutoConfiguration.class) @EnableConfigurationProperties(DataSourceProperties.class) -@ConditionalOnClass({ DataSource.class, TransactionManager.class }) +@ConditionalOnClass({ DataSource.class, TransactionManager.class, + EmbeddedDatabaseType.class }) @ConditionalOnBean(XADataSourceWrapper.class) @ConditionalOnMissingBean(DataSource.class) public class XADataSourceAutoConfiguration implements BeanClassLoaderAware { diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java index 65ee8083f5..d55074d18a 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jta; import java.io.File; import java.util.Properties; +import javax.jms.Message; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; @@ -51,7 +52,7 @@ import com.atomikos.icatch.jta.UserTransactionManager; * @since 1.2.0 */ @Configuration -@ConditionalOnClass(UserTransactionManager.class) +@ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class }) @ConditionalOnMissingBean(PlatformTransactionManager.class) class AtomikosJtaConfiguration { @@ -99,12 +100,6 @@ class AtomikosJtaConfiguration { return new AtomikosXADataSourceWrapper(); } - @Bean - @ConditionalOnMissingBean - public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() { - return new AtomikosXAConnectionFactoryWrapper(); - } - @Bean @ConditionalOnMissingBean public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() { @@ -117,4 +112,16 @@ class AtomikosJtaConfiguration { return new JtaTransactionManager(userTransaction, transactionManager); } + @Configuration + @ConditionalOnClass(Message.class) + static class AtomikosJtaJmsConfiguration { + + @Bean + @ConditionalOnMissingBean + public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() { + return new AtomikosXAConnectionFactoryWrapper(); + } + + } + } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java index eff02e143a..dfb674f740 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jta; import java.io.File; +import javax.jms.Message; import javax.transaction.TransactionManager; import org.springframework.beans.factory.annotation.Autowired; @@ -47,7 +48,7 @@ import bitronix.tm.jndi.BitronixContext; * @since 1.2.0 */ @Configuration -@ConditionalOnClass(BitronixContext.class) +@ConditionalOnClass({ JtaTransactionManager.class, BitronixContext.class }) @ConditionalOnMissingBean(PlatformTransactionManager.class) class BitronixJtaConfiguration { @@ -89,12 +90,6 @@ class BitronixJtaConfiguration { return new BitronixXADataSourceWrapper(); } - @Bean - @ConditionalOnMissingBean - public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() { - return new BitronixXAConnectionFactoryWrapper(); - } - @Bean @ConditionalOnMissingBean public static BitronixDependentBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() { @@ -106,4 +101,13 @@ class BitronixJtaConfiguration { return new JtaTransactionManager(transactionManager); } + @ConditionalOnClass(Message.class) + static class BitronixJtaJmsConfiguration { + + @Bean + @ConditionalOnMissingBean + public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() { + return new BitronixXAConnectionFactoryWrapper(); + } + } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java index 92f7558942..1ae8bad3c0 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.jta; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -24,12 +25,13 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; /** - * JTA Configuration for a JDNI managed {@link JtaTransactionManager}. + * JTA Configuration for a JNDI-managed {@link JtaTransactionManager}. * * @author Phillip Webb * @since 1.2.0 */ @Configuration +@ConditionalOnClass(JtaTransactionManager.class) @ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, "java:comp/TransactionManager", "java:appserver/TransactionManager", "java:pm/TransactionManager", "java:/TransactionManager" }) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java index f07097a6b2..72dcec28d0 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java @@ -61,7 +61,7 @@ public class JtaAutoConfigurationTests { } @Test - public void customPatformTransactionManager() throws Exception { + public void customPlatformTransactionManager() throws Exception { this.context = new AnnotationConfigApplicationContext( CustomTransactionManagerConfig.class, JtaAutoConfiguration.class); this.thrown.expect(NoSuchBeanDefinitionException.class); diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java index 4d0fdc22dd..9be8e633ab 100644 --- a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java @@ -94,6 +94,9 @@ public class AtomikosDependsOnBeanFactoryPostProcessor implements catch (ClassNotFoundException ex) { // Ignore } + catch (NoClassDefFoundError ex) { + // Ignore + } return NO_BEANS; } diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixDependentBeanFactoryPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixDependentBeanFactoryPostProcessor.java index df800b196a..2ce3b8a229 100644 --- a/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixDependentBeanFactoryPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixDependentBeanFactoryPostProcessor.java @@ -70,6 +70,9 @@ public class BitronixDependentBeanFactoryPostProcessor implements catch (ClassNotFoundException ex) { // Ignore } + catch (NoClassDefFoundError ex) { + // Ignore + } return NO_BEANS; }