diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfiguration.java index 1f461921f0..2566888027 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfiguration.java @@ -20,8 +20,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import io.r2dbc.spi.ConnectionFactory; - import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -34,15 +32,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.convert.CustomConversions; import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; -import org.springframework.data.r2dbc.core.DatabaseClient; import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; import org.springframework.data.r2dbc.dialect.DialectResolver; import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; -import org.springframework.data.r2dbc.support.R2dbcExceptionSubclassTranslator; -import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator; import org.springframework.data.relational.core.mapping.NamingStrategy; +import org.springframework.r2dbc.core.DatabaseClient; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link DatabaseClient}. @@ -52,24 +49,21 @@ import org.springframework.data.relational.core.mapping.NamingStrategy; * @since 2.3.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass(DatabaseClient.class) -@ConditionalOnMissingBean(DatabaseClient.class) -@ConditionalOnSingleCandidate(ConnectionFactory.class) +@ConditionalOnClass({ DatabaseClient.class, R2dbcEntityTemplate.class }) +@ConditionalOnSingleCandidate(DatabaseClient.class) @AutoConfigureAfter(R2dbcAutoConfiguration.class) public class R2dbcDataAutoConfiguration { - private final ConnectionFactory connectionFactory; + private final DatabaseClient databaseClient; - public R2dbcDataAutoConfiguration(ConnectionFactory connectionFactory) { - this.connectionFactory = connectionFactory; + public R2dbcDataAutoConfiguration(DatabaseClient databaseClient) { + this.databaseClient = databaseClient; } @Bean @ConditionalOnMissingBean - public DatabaseClient r2dbcDatabaseClient(ReactiveDataAccessStrategy dataAccessStrategy, - R2dbcExceptionTranslator exceptionTranslator) { - return DatabaseClient.builder().connectionFactory(this.connectionFactory).dataAccessStrategy(dataAccessStrategy) - .exceptionTranslator(exceptionTranslator).build(); + public R2dbcEntityTemplate r2dbcEntityTemplate(ReactiveDataAccessStrategy reactiveDataAccessStrategy) { + return new R2dbcEntityTemplate(this.databaseClient, reactiveDataAccessStrategy); } @Bean @@ -87,13 +81,13 @@ public class R2dbcDataAutoConfiguration { public ReactiveDataAccessStrategy reactiveDataAccessStrategy(R2dbcMappingContext mappingContext, R2dbcCustomConversions r2dbcCustomConversions) { MappingR2dbcConverter converter = new MappingR2dbcConverter(mappingContext, r2dbcCustomConversions); - return new DefaultReactiveDataAccessStrategy(DialectResolver.getDialect(this.connectionFactory), converter); + return new DefaultReactiveDataAccessStrategy(getDialect(), converter); } @Bean @ConditionalOnMissingBean public R2dbcCustomConversions r2dbcCustomConversions() { - R2dbcDialect dialect = DialectResolver.getDialect(this.connectionFactory); + R2dbcDialect dialect = getDialect(); List converters = new ArrayList<>(dialect.getConverters()); converters.addAll(R2dbcCustomConversions.STORE_CONVERTERS); return new R2dbcCustomConversions( @@ -101,10 +95,8 @@ public class R2dbcDataAutoConfiguration { Collections.emptyList()); } - @Bean - @ConditionalOnMissingBean - public R2dbcExceptionTranslator r2dbcExceptionTranslator() { - return new R2dbcExceptionSubclassTranslator(); + private R2dbcDialect getDialect() { + return DialectResolver.getDialect(this.databaseClient.getConnectionFactory()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfiguration.java index 46638e8f24..402f2edac9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfiguration.java @@ -26,10 +26,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.data.r2dbc.core.DatabaseClient; import org.springframework.data.r2dbc.repository.R2dbcRepository; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean; +import org.springframework.r2dbc.core.DatabaseClient; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Data R2DBC Repositories. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryDependentConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryDependentConfiguration.java new file mode 100644 index 0000000000..0b5c01858a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryDependentConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2020 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.autoconfigure.r2dbc; + +import io.r2dbc.spi.ConnectionFactory; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.r2dbc.core.DatabaseClient; + +/** + * Configuration of the R2DBC infrastructure based on a {@link ConnectionFactory}. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(DatabaseClient.class) +@ConditionalOnSingleCandidate(ConnectionFactory.class) +class ConnectionFactoryDependentConfiguration { + + @Bean + @ConditionalOnMissingBean + DatabaseClient r2dbcDatabaseClient(ConnectionFactory connectionFactory) { + return DatabaseClient.builder().connectionFactory(connectionFactory).build(); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java index 31dd8e381f..11f50c9621 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java @@ -37,7 +37,8 @@ import org.springframework.context.annotation.Import; @ConditionalOnClass(ConnectionFactory.class) @AutoConfigureBefore(DataSourceAutoConfiguration.class) @EnableConfigurationProperties(R2dbcProperties.class) -@Import({ ConnectionFactoryConfigurations.Pool.class, ConnectionFactoryConfigurations.Generic.class }) +@Import({ ConnectionFactoryConfigurations.Pool.class, ConnectionFactoryConfigurations.Generic.class, + ConnectionFactoryDependentConfiguration.class }) public class R2dbcAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcTransactionManagerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcTransactionManagerAutoConfiguration.java similarity index 93% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcTransactionManagerAutoConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcTransactionManagerAutoConfiguration.java index 0de28c6226..3b963f2bd0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcTransactionManagerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcTransactionManagerAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.data.r2dbc; +package org.springframework.boot.autoconfigure.r2dbc; import io.r2dbc.spi.ConnectionFactory; @@ -28,7 +28,7 @@ import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfigu import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; -import org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager; +import org.springframework.r2dbc.connection.R2dbcTransactionManager; import org.springframework.transaction.ReactiveTransactionManager; /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index fdd60832eb..aa05666227 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -57,7 +57,6 @@ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfigura org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\ -org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ @@ -106,6 +105,7 @@ org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\ +org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfigurationTests.java index 682ed667af..8a3b8d6733 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcDataAutoConfigurationTests.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; import static org.assertj.core.api.Assertions.assertThat; @@ -36,8 +36,8 @@ class R2dbcDataAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class, R2dbcDataAutoConfiguration.class)); @Test - void databaseClientExists() { - this.contextRunner.run((context) -> assertThat(context).hasSingleBean(DatabaseClient.class)); + void r2dbcEntityTemplateIsConfigured() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(R2dbcEntityTemplate.class)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfigurationTests.java index 1eb702dd5f..99e372dc80 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcRepositoriesAutoConfigurationTests.java @@ -23,19 +23,21 @@ import reactor.test.StepVerifier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; import org.springframework.boot.autoconfigure.data.r2dbc.city.City; import org.springframework.boot.autoconfigure.data.r2dbc.city.CityRepository; import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; -import org.springframework.data.r2dbc.core.DatabaseClient; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.repository.config.R2dbcRepositoryConfigurationExtension; import org.springframework.data.repository.Repository; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; +import org.springframework.r2dbc.core.DatabaseClient; import static org.assertj.core.api.Assertions.assertThat; @@ -58,6 +60,7 @@ class R2dbcRepositoriesAutoConfigurationTests { @Test void backsOffWithNoDatabaseClientOperations() { this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader("org.springframework.r2dbc")) .withUserConfiguration(TestConfiguration.class).run((context) -> { assertThat(context).doesNotHaveBean(DatabaseClient.class); assertThat(context).doesNotHaveBean(R2dbcRepositoryConfigurationExtension.class); @@ -105,7 +108,7 @@ class R2dbcRepositoriesAutoConfigurationTests { ResourceLoader resourceLoader = new DefaultResourceLoader(); Resource[] scripts = new Resource[] { resourceLoader.getResource("classpath:data-city-schema.sql"), resourceLoader.getResource("classpath:city.sql") }; - new ResourceDatabasePopulator(scripts).execute(connectionFactory).block(); + new ResourceDatabasePopulator(scripts).populate(connectionFactory).block(); } } @@ -117,6 +120,7 @@ class R2dbcRepositoriesAutoConfigurationTests { } @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(EmptyDataPackage.class) static class EmptyConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java index f8734fde94..61cafd2c89 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java @@ -39,6 +39,7 @@ import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.r2dbc.core.DatabaseClient; import static org.assertj.core.api.Assertions.assertThat; @@ -240,6 +241,24 @@ class R2dbcAutoConfigurationTests { .doesNotHaveBean(DataSource.class)); } + @Test + void databaseClientIsConfigured() { + this.contextRunner.withPropertyValues("spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName()) + .run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(DatabaseClient.class); + assertThat(context.getBean(DatabaseClient.class).getConnectionFactory()) + .isSameAs(context.getBean(ConnectionFactory.class)); + }); + } + + @Test + void databaseClientBacksOffIfSpringR2dbcIsNotAvailable() { + this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.r2dbc")) + .withPropertyValues("spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName()) + .run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class) + .doesNotHaveBean(DatabaseClient.class)); + } + private String randomDatabaseName() { return "testdb-" + UUID.randomUUID(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcTransactionManagerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcTransactionManagerAutoConfigurationTests.java similarity index 95% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcTransactionManagerAutoConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcTransactionManagerAutoConfigurationTests.java index b0fda814bd..7b1cdf0dd6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/r2dbc/R2dbcTransactionManagerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcTransactionManagerAutoConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.data.r2dbc; +package org.springframework.boot.autoconfigure.r2dbc; import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactory; @@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfigu import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager; import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Transactional; @@ -39,7 +38,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; /** - * Tests for {@link R2dbcTransactionManager}. + * Tests for {@link R2dbcTransactionManagerAutoConfiguration}. * * @author Mark Paluch * @author Oliver Drotbohm diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/SimpleBindMarkerFactoryProvider.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/SimpleBindMarkerFactoryProvider.java new file mode 100644 index 0000000000..8fbd3a47db --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/SimpleBindMarkerFactoryProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2020 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.autoconfigure.r2dbc; + +import io.r2dbc.pool.ConnectionPool; +import io.r2dbc.spi.ConnectionFactory; + +import org.springframework.boot.autoconfigure.r2dbc.SimpleConnectionFactoryProvider.SimpleTestConnectionFactory; +import org.springframework.r2dbc.core.binding.BindMarkersFactory; +import org.springframework.r2dbc.core.binding.BindMarkersFactoryResolver.BindMarkerFactoryProvider; + +/** + * Simple {@link BindMarkerFactoryProvider} for {@link SimpleConnectionFactoryProvider}. + * + * @author Stephane Nicoll + */ +public class SimpleBindMarkerFactoryProvider implements BindMarkerFactoryProvider { + + @Override + public BindMarkersFactory getBindMarkers(ConnectionFactory connectionFactory) { + if (unwrapIfNecessary(connectionFactory) instanceof SimpleTestConnectionFactory) { + return BindMarkersFactory.anonymous("?"); + } + return null; + } + + private ConnectionFactory unwrapIfNecessary(ConnectionFactory connectionFactory) { + if (connectionFactory instanceof ConnectionPool) { + return ((ConnectionPool) connectionFactory).unwrap(); + } + return connectionFactory; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring.factories new file mode 100644 index 0000000000..8f545e4f68 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.r2dbc.core.binding.BindMarkersFactoryResolver$BindMarkerFactoryProvider=org.springframework.boot.autoconfigure.r2dbc.SimpleBindMarkerFactoryProvider diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc index 12d189b868..2d748fe2be 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc @@ -1972,7 +1972,7 @@ You can tune that behavior by setting `spring.datasource.continue-on-error`. === Initialize a Database Using R2DBC If you are using R2DBC, the regular `DataSource` auto-configuration backs off so none of the options described above can be used. -If you are using Spring Data R2DBC, you can initialize the database on startup using SQL scripts as shown in the following example: +You can initialize the database on startup using SQL scripts as shown in the following example: [source,java,indent=0] ---- diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index ab0b3579dd..24a7c673f1 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -4215,7 +4215,7 @@ If you want to make sure that each context has a separate embedded database, you [[boot-features-r2dbc-using-database-client]] ==== Using DatabaseClient -Spring Data's `DatabaseClient` class is auto-configured, and you can `@Autowire` it directly into your own beans, as shown in the following example: +A `DatabaseClient` bean is auto-configured, and you can `@Autowire` it directly into your own beans, as shown in the following example: [source,java,indent=0] ---- diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/r2dbc/R2dbcDatabaseInitializationExample.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/r2dbc/R2dbcDatabaseInitializationExample.java index 2f94827545..e5236b2b91 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/r2dbc/R2dbcDatabaseInitializationExample.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/r2dbc/R2dbcDatabaseInitializationExample.java @@ -23,7 +23,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; /** * Example configuration for initializing a database using R2DBC. @@ -41,7 +41,7 @@ public class R2dbcDatabaseInitializationExample { ResourceLoader resourceLoader = new DefaultResourceLoader(); Resource[] scripts = new Resource[] { resourceLoader.getResource("classpath:schema.sql"), resourceLoader.getResource("classpath:data.sql") }; - new ResourceDatabasePopulator(scripts).execute(connectionFactory).block(); + new ResourceDatabasePopulator(scripts).populate(connectionFactory).block(); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index 9034663f25..5cd46713db 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -52,11 +52,11 @@ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration # AutoConfigureDataR2dbc auto-configuration imports org.springframework.boot.test.autoconfigure.data.r2dbc.AutoConfigureDataR2dbc=\ org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\ -org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\ +org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration # AutoConfigureDataRedis auto-configuration imports diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/r2dbc/DataR2dbcTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/r2dbc/DataR2dbcTestIntegrationTests.java index 0cc556e34d..39158181b2 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/r2dbc/DataR2dbcTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/r2dbc/DataR2dbcTestIntegrationTests.java @@ -26,8 +26,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; -import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; +import org.springframework.r2dbc.core.DatabaseClient; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class DataR2dbcTestIntegrationTests { @Test void testDatabaseClient() { - this.databaseClient.execute("SELECT * FROM example").fetch().all().as(StepVerifier::create).verifyComplete(); + this.databaseClient.sql("SELECT * FROM example").fetch().all().as(StepVerifier::create).verifyComplete(); } @Test @@ -72,7 +72,7 @@ class DataR2dbcTestIntegrationTests { ResourceLoader resourceLoader = new DefaultResourceLoader(); Resource[] scripts = new Resource[] { resourceLoader .getResource("classpath:org/springframework/boot/test/autoconfigure/data/r2dbc/schema.sql") }; - new ResourceDatabasePopulator(scripts).execute(connectionFactory).block(); + new ResourceDatabasePopulator(scripts).populate(connectionFactory).block(); } } diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/SampleR2dbcApplication.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/SampleR2dbcApplication.java index 48665a74c6..2b75343e8e 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/SampleR2dbcApplication.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/SampleR2dbcApplication.java @@ -24,7 +24,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; @SpringBootApplication public class SampleR2dbcApplication { @@ -37,7 +37,7 @@ public class SampleR2dbcApplication { public ApplicationRunner initializeDatabase(ConnectionFactory connectionFactory, ResourceLoader resourceLoader) { return (arguments) -> { Resource[] scripts = new Resource[] { resourceLoader.getResource("classpath:database-init.sql") }; - new ResourceDatabasePopulator(scripts).execute(connectionFactory).block(); + new ResourceDatabasePopulator(scripts).populate(connectionFactory).block(); }; }