Commit 6f9f335e authored by Andy Wilkinson's avatar Andy Wilkinson

Add additional class conditions for JTA auto-configuration

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
parent 59ce6344
...@@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; ...@@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
/** /**
...@@ -38,7 +39,7 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; ...@@ -38,7 +39,7 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
@Configuration @Configuration
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class, @AutoConfigureBefore({ XADataSourceAutoConfiguration.class,
DataSourceAutoConfiguration.class }) DataSourceAutoConfiguration.class })
@ConditionalOnClass(DataSource.class) @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnProperty(prefix = DataSourceProperties.PREFIX, name = "jndi-name") @ConditionalOnProperty(prefix = DataSourceProperties.PREFIX, name = "jndi-name")
@EnableConfigurationProperties(DataSourceProperties.class) @EnableConfigurationProperties(DataSourceProperties.class)
public class JndiDataSourceAutoConfiguration { public class JndiDataSourceAutoConfiguration {
......
...@@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; ...@@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.XADataSourceWrapper; import org.springframework.boot.jta.XADataSourceWrapper;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -50,7 +51,8 @@ import org.springframework.util.StringUtils; ...@@ -50,7 +51,8 @@ import org.springframework.util.StringUtils;
@AutoConfigureBefore(DataSourceAutoConfiguration.class) @AutoConfigureBefore(DataSourceAutoConfiguration.class)
@AutoConfigureAfter(JtaAutoConfiguration.class) @AutoConfigureAfter(JtaAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class) @EnableConfigurationProperties(DataSourceProperties.class)
@ConditionalOnClass({ DataSource.class, TransactionManager.class }) @ConditionalOnClass({ DataSource.class, TransactionManager.class,
EmbeddedDatabaseType.class })
@ConditionalOnBean(XADataSourceWrapper.class) @ConditionalOnBean(XADataSourceWrapper.class)
@ConditionalOnMissingBean(DataSource.class) @ConditionalOnMissingBean(DataSource.class)
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware { public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {
......
...@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jta; ...@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jta;
import java.io.File; import java.io.File;
import java.util.Properties; import java.util.Properties;
import javax.jms.Message;
import javax.transaction.TransactionManager; import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
...@@ -51,7 +52,7 @@ import com.atomikos.icatch.jta.UserTransactionManager; ...@@ -51,7 +52,7 @@ import com.atomikos.icatch.jta.UserTransactionManager;
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration @Configuration
@ConditionalOnClass(UserTransactionManager.class) @ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
class AtomikosJtaConfiguration { class AtomikosJtaConfiguration {
...@@ -99,12 +100,6 @@ class AtomikosJtaConfiguration { ...@@ -99,12 +100,6 @@ class AtomikosJtaConfiguration {
return new AtomikosXADataSourceWrapper(); return new AtomikosXADataSourceWrapper();
} }
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new AtomikosXAConnectionFactoryWrapper();
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() { public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
...@@ -117,4 +112,16 @@ class AtomikosJtaConfiguration { ...@@ -117,4 +112,16 @@ class AtomikosJtaConfiguration {
return new JtaTransactionManager(userTransaction, transactionManager); return new JtaTransactionManager(userTransaction, transactionManager);
} }
@Configuration
@ConditionalOnClass(Message.class)
static class AtomikosJtaJmsConfiguration {
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new AtomikosXAConnectionFactoryWrapper();
}
}
} }
...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jta; ...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jta;
import java.io.File; import java.io.File;
import javax.jms.Message;
import javax.transaction.TransactionManager; import javax.transaction.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -47,7 +48,7 @@ import bitronix.tm.jndi.BitronixContext; ...@@ -47,7 +48,7 @@ import bitronix.tm.jndi.BitronixContext;
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration @Configuration
@ConditionalOnClass(BitronixContext.class) @ConditionalOnClass({ JtaTransactionManager.class, BitronixContext.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
class BitronixJtaConfiguration { class BitronixJtaConfiguration {
...@@ -89,12 +90,6 @@ class BitronixJtaConfiguration { ...@@ -89,12 +90,6 @@ class BitronixJtaConfiguration {
return new BitronixXADataSourceWrapper(); return new BitronixXADataSourceWrapper();
} }
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new BitronixXAConnectionFactoryWrapper();
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public static BitronixDependentBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() { public static BitronixDependentBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
...@@ -106,4 +101,13 @@ class BitronixJtaConfiguration { ...@@ -106,4 +101,13 @@ class BitronixJtaConfiguration {
return new JtaTransactionManager(transactionManager); return new JtaTransactionManager(transactionManager);
} }
@ConditionalOnClass(Message.class)
static class BitronixJtaJmsConfiguration {
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new BitronixXAConnectionFactoryWrapper();
}
}
} }
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.jta; 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.ConditionalOnJndi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -24,12 +25,13 @@ import org.springframework.transaction.PlatformTransactionManager; ...@@ -24,12 +25,13 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager; 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 * @author Phillip Webb
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration @Configuration
@ConditionalOnClass(JtaTransactionManager.class)
@ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, @ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME,
"java:comp/TransactionManager", "java:appserver/TransactionManager", "java:comp/TransactionManager", "java:appserver/TransactionManager",
"java:pm/TransactionManager", "java:/TransactionManager" }) "java:pm/TransactionManager", "java:/TransactionManager" })
......
...@@ -61,7 +61,7 @@ public class JtaAutoConfigurationTests { ...@@ -61,7 +61,7 @@ public class JtaAutoConfigurationTests {
} }
@Test @Test
public void customPatformTransactionManager() throws Exception { public void customPlatformTransactionManager() throws Exception {
this.context = new AnnotationConfigApplicationContext( this.context = new AnnotationConfigApplicationContext(
CustomTransactionManagerConfig.class, JtaAutoConfiguration.class); CustomTransactionManagerConfig.class, JtaAutoConfiguration.class);
this.thrown.expect(NoSuchBeanDefinitionException.class); this.thrown.expect(NoSuchBeanDefinitionException.class);
......
...@@ -94,6 +94,9 @@ public class AtomikosDependsOnBeanFactoryPostProcessor implements ...@@ -94,6 +94,9 @@ public class AtomikosDependsOnBeanFactoryPostProcessor implements
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// Ignore // Ignore
} }
catch (NoClassDefFoundError ex) {
// Ignore
}
return NO_BEANS; return NO_BEANS;
} }
......
...@@ -70,6 +70,9 @@ public class BitronixDependentBeanFactoryPostProcessor implements ...@@ -70,6 +70,9 @@ public class BitronixDependentBeanFactoryPostProcessor implements
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// Ignore // Ignore
} }
catch (NoClassDefFoundError ex) {
// Ignore
}
return NO_BEANS; return NO_BEANS;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment