diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java index 3326fc7541a..fb876bee8eb 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java @@ -61,7 +61,7 @@ import org.springframework.util.Assert; * @author Andy Wilkinson * @since 1.3.3 */ -@ConditionalOnClass(DataSource.class) +@ConditionalOnClass({ DataSource.class, DataSourceProperties.class }) @ConditionalOnEnabledDevTools @Conditional(DevToolsDataSourceCondition.class) @AutoConfiguration(afterName = "org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration") diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfiguration.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfiguration.java index d544d5d077a..21f2000362a 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfiguration.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfiguration.java @@ -51,7 +51,7 @@ import org.springframework.util.Assert; * @author Phillip Webb * @since 2.5.6 */ -@ConditionalOnClass(ConnectionFactory.class) +@ConditionalOnClass({ ConnectionFactory.class, R2dbcAutoConfiguration.class }) @ConditionalOnEnabledDevTools @Conditional(DevToolsConnectionFactoryCondition.class) @AutoConfiguration(afterName = "org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration") diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsAutoConfigurationTests.java new file mode 100644 index 00000000000..17bac765e4e --- /dev/null +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsAutoConfigurationTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.devtools.autoconfigure; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Base class for tests for {@link DevToolsDataSourceAutoConfiguration}. + * + * @author Stephane Nicoll + */ +abstract class AbstractDevToolsAutoConfigurationTests { + + /** + * Create an {@link AssertableApplicationContext} from the given {@code supplier}. + *

+ * Devtools auto-configuration backs-off when it detects JUnit in the call stack. This + * method initializes the context in a separate thread to ignore that particular + * condition. + * @param supplier a supplier of the context + * @return an assertable context + */ + protected AssertableApplicationContext getContext(Supplier supplier) + throws Exception { + AtomicReference atomicReference = new AtomicReference<>(); + Thread thread = new Thread(() -> { + ConfigurableApplicationContext context = supplier.get(); + atomicReference.getAndSet(context); + }); + thread.start(); + thread.join(); + return AssertableApplicationContext.get(atomicReference::get); + } + +} diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java index 46726c8fb6b..81377ae334a 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java @@ -20,8 +20,6 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; import javax.sql.DataSource; @@ -38,7 +36,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; import static org.mockito.BDDMockito.willReturn; @@ -51,7 +48,7 @@ import static org.mockito.Mockito.spy; * * @author Andy Wilkinson */ -abstract class AbstractDevToolsDataSourceAutoConfigurationTests { +abstract class AbstractDevToolsDataSourceAutoConfigurationTests extends AbstractDevToolsAutoConfigurationTests { @Test void singleManuallyConfiguredDataSourceIsNotClosed() throws Exception { @@ -94,20 +91,6 @@ abstract class AbstractDevToolsDataSourceAutoConfigurationTests { return statement; } - protected ConfigurableApplicationContext getContext(Supplier supplier) - throws Exception { - AtomicReference atomicReference = new AtomicReference<>(); - Thread thread = new Thread(() -> { - ConfigurableApplicationContext context = supplier.get(); - atomicReference.getAndSet(context); - }); - thread.start(); - thread.join(); - ConfigurableApplicationContext context = atomicReference.get(); - assertThat(context).isNotNull(); - return context; - } - protected final ConfigurableApplicationContext createContext(Class... classes) { return createContext(null, classes); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationWithoutSpringBootJdbcTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationWithoutSpringBootJdbcTests.java new file mode 100644 index 00000000000..6dc17635ff6 --- /dev/null +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationWithoutSpringBootJdbcTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.devtools.autoconfigure; + +import javax.sql.DataSource; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration.NonEmbeddedInMemoryDatabaseShutdownExecutor; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.testsupport.classpath.ClassPathExclusions; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link DevToolsDataSourceAutoConfiguration} when {@code spring-boot-jdbc} is + * not on the classpath. + * + * @author Kosuke Yanagihara + */ +@ClassPathExclusions(packages = "org.springframework.boot.jdbc.autoconfigure") +class DevToolsDataSourceAutoConfigurationWithoutSpringBootJdbcTests extends AbstractDevToolsAutoConfigurationTests { + + @Test + void backsOffWithSingleManuallyConfiguredDataSource() throws Exception { + try (AssertableApplicationContext context = getContext( + () -> new AnnotationConfigApplicationContext(SingleDataSourceConfiguration.class))) { + assertThat(context).hasSingleBean(DataSource.class) + .doesNotHaveBean(NonEmbeddedInMemoryDatabaseShutdownExecutor.class); + } + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(DevToolsDataSourceAutoConfiguration.class) + static class SingleDataSourceConfiguration { + + @Bean + DataSource dataSource() { + return mock(DataSource.class); + } + + } + +} diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java index 61c0983f006..01f4ec8f797 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java @@ -30,9 +30,12 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.devtools.autoconfigure.DevToolsR2dbcAutoConfiguration.InMemoryR2dbcDatabaseShutdownExecutor; import org.springframework.boot.devtools.autoconfigure.DevToolsR2dbcAutoConfiguration.R2dbcDatabaseShutdownEvent; import org.springframework.boot.r2dbc.SimpleConnectionFactoryProvider.SimpleTestConnectionFactory; import org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.testsupport.classpath.ClassPathExclusions; import org.springframework.context.ApplicationListener; @@ -40,6 +43,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -49,7 +53,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Phillip Webb */ -class DevToolsR2dbcAutoConfigurationTests { +class DevToolsR2dbcAutoConfigurationTests extends AbstractDevToolsAutoConfigurationTests { static List shutdowns = Collections.synchronizedList(new ArrayList<>()); @@ -166,6 +170,28 @@ class DevToolsR2dbcAutoConfigurationTests { } + @Nested + @ClassPathExclusions(packages = "org.springframework.boot.r2dbc.autoconfigure") + class WithoutSpringBootR2dbc { + + @Test + void backsOffWithSingleManuallyConfiguredConnectionFactory() throws Exception { + try (AssertableApplicationContext context = getContext(() -> new AnnotationConfigApplicationContext( + SingleConnectionFactoryWithDevToolsConfiguration.class))) { + assertThat(context).hasSingleBean(ConnectionFactory.class) + .doesNotHaveBean(InMemoryR2dbcDatabaseShutdownExecutor.class); + } + } + + } + + @Configuration(proxyBeanMethods = false) + @Import(SingleConnectionFactoryConfiguration.class) + @ImportAutoConfiguration(DevToolsR2dbcAutoConfiguration.class) + static class SingleConnectionFactoryWithDevToolsConfiguration { + + } + @Configuration(proxyBeanMethods = false) static class SingleConnectionFactoryConfiguration {