Add auto-configuration for Spring Data R2DBC
This commit adds auto-configuration support for Spring Data R2DBC. If a `ConnectionFactory` and Spring Data are available, scanning of reactive repositories is enabled. This commit also adds a starter to bring R2DBC and the necessary Spring Data libraries. See gh-19988 Co-authored-by: Mark Paluch <mpaluch@pivotal.io> Co-authored-by: Oliver Drotbohm <odrotbohm@pivotal.io>
This commit is contained in:
parent
5c174feb65
commit
19fbac7d59
|
|
@ -123,6 +123,7 @@ dependencies {
|
|||
optional("org.springframework.data:spring-data-ldap")
|
||||
optional("org.springframework.data:spring-data-mongodb")
|
||||
optional("org.springframework.data:spring-data-neo4j")
|
||||
optional("org.springframework.data:spring-data-r2dbc")
|
||||
optional("org.springframework.data:spring-data-redis")
|
||||
optional("org.springframework.data:spring-data-solr")
|
||||
optional("org.springframework.hateoas:spring-hateoas")
|
||||
|
|
@ -158,6 +159,7 @@ dependencies {
|
|||
testImplementation("com.jayway.jsonpath:json-path")
|
||||
testImplementation("com.squareup.okhttp3:mockwebserver")
|
||||
testImplementation("com.sun.xml.messaging.saaj:saaj-impl")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
testImplementation("io.r2dbc:r2dbc-h2")
|
||||
testImplementation("jakarta.json:jakarta.json-api")
|
||||
testImplementation("jakarta.xml.ws:jakarta.xml.ws-api")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
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;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link DatabaseClient}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(DatabaseClient.class)
|
||||
@ConditionalOnMissingBean(DatabaseClient.class)
|
||||
@ConditionalOnSingleCandidate(ConnectionFactory.class)
|
||||
@AutoConfigureAfter(R2dbcAutoConfiguration.class)
|
||||
public class R2dbcDataAutoConfiguration {
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
|
||||
public R2dbcDataAutoConfiguration(ConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DatabaseClient r2dbcDatabaseClient(ReactiveDataAccessStrategy dataAccessStrategy,
|
||||
R2dbcExceptionTranslator exceptionTranslator) {
|
||||
return DatabaseClient.builder().connectionFactory(this.connectionFactory).dataAccessStrategy(dataAccessStrategy)
|
||||
.exceptionTranslator(exceptionTranslator).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public R2dbcMappingContext r2dbcMappingContext(ObjectProvider<NamingStrategy> namingStrategy,
|
||||
R2dbcCustomConversions r2dbcCustomConversions) {
|
||||
R2dbcMappingContext relationalMappingContext = new R2dbcMappingContext(
|
||||
namingStrategy.getIfAvailable(() -> NamingStrategy.INSTANCE));
|
||||
relationalMappingContext.setSimpleTypeHolder(r2dbcCustomConversions.getSimpleTypeHolder());
|
||||
return relationalMappingContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveDataAccessStrategy reactiveDataAccessStrategy(R2dbcMappingContext mappingContext,
|
||||
R2dbcCustomConversions r2dbcCustomConversions) {
|
||||
MappingR2dbcConverter converter = new MappingR2dbcConverter(mappingContext, r2dbcCustomConversions);
|
||||
return new DefaultReactiveDataAccessStrategy(DialectResolver.getDialect(this.connectionFactory), converter);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public R2dbcCustomConversions r2dbcCustomConversions() {
|
||||
R2dbcDialect dialect = DialectResolver.getDialect(this.connectionFactory);
|
||||
List<Object> converters = new ArrayList<>(dialect.getConverters());
|
||||
converters.addAll(R2dbcCustomConversions.STORE_CONVERTERS);
|
||||
return new R2dbcCustomConversions(
|
||||
CustomConversions.StoreConversions.of(dialect.getSimpleTypeHolder(), converters),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public R2dbcExceptionTranslator r2dbcExceptionTranslator() {
|
||||
return new R2dbcExceptionSubclassTranslator();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
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;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data R2DBC Repositories.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see EnableR2dbcRepositories
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ ConnectionFactory.class, R2dbcRepository.class })
|
||||
@ConditionalOnBean(DatabaseClient.class)
|
||||
@ConditionalOnProperty(prefix = "spring.data.r2dbc.repositories", name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
@ConditionalOnMissingBean(R2dbcRepositoryFactoryBean.class)
|
||||
@Import(R2dbcRepositoriesAutoConfigureRegistrar.class)
|
||||
@AutoConfigureAfter(R2dbcDataAutoConfiguration.class)
|
||||
public class R2dbcRepositoriesAutoConfiguration {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
|
||||
import org.springframework.data.r2dbc.repository.config.R2dbcRepositoryConfigurationExtension;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
|
||||
/**
|
||||
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data R2DBC
|
||||
* Repositories.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class R2dbcRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport {
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableR2dbcRepositories.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getConfiguration() {
|
||||
return EnableR2dbcRepositoriesConfiguration.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
|
||||
return new R2dbcRepositoryConfigurationExtension();
|
||||
}
|
||||
|
||||
@EnableR2dbcRepositories
|
||||
private static class EnableR2dbcRepositoriesConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
|
||||
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.transaction.ReactiveTransactionManager;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link R2dbcTransactionManager}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ R2dbcTransactionManager.class, ReactiveTransactionManager.class })
|
||||
@ConditionalOnSingleCandidate(ConnectionFactory.class)
|
||||
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
|
||||
@AutoConfigureBefore(TransactionAutoConfiguration.class)
|
||||
public class R2dbcTransactionManagerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ReactiveTransactionManager.class)
|
||||
public R2dbcTransactionManager connectionFactoryTransactionManager(ConnectionFactory connectionFactory) {
|
||||
return new R2dbcTransactionManager(connectionFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-Configuration for Spring Data R2DBC.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.data.r2dbc;
|
||||
|
|
@ -418,6 +418,12 @@
|
|||
"description": "Whether to enable Neo4j repositories.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.data.r2dbc.repositories.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable R2DBC repositories.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.data.redis.repositories.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfigura
|
|||
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
|
||||
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,\
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -112,7 +112,7 @@ class JdbcRepositoriesAutoConfigurationTests {
|
|||
|
||||
private Function<ApplicationContextRunner, ApplicationContextRunner> database() {
|
||||
return (runner) -> runner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.schema=classpath:data-jdbc-schema.sql",
|
||||
.withPropertyValues("spring.datasource.schema=classpath:data-city-schema.sql",
|
||||
"spring.datasource.data=classpath:city.sql", "spring.datasource.generate-unique-name:true");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link R2dbcDataAutoConfiguration}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class R2dbcDataAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class, R2dbcDataAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void databaseClientExists() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(DatabaseClient.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.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.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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link R2dbcRepositoriesAutoConfiguration}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class R2dbcRepositoriesAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(R2dbcRepositoriesAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void backsOffWithNoConnectionFactory() {
|
||||
this.contextRunner.withUserConfiguration(TestConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(R2dbcRepositoryConfigurationExtension.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void backsOffWithNoDatabaseClientOperations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.withUserConfiguration(TestConfiguration.class).run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(DatabaseClient.class);
|
||||
assertThat(context).doesNotHaveBean(R2dbcRepositoryConfigurationExtension.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicAutoConfiguration() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(R2dbcAutoConfiguration.class, R2dbcDataAutoConfiguration.class))
|
||||
.withUserConfiguration(DatabaseInitializationConfiguration.class, TestConfiguration.class)
|
||||
.withPropertyValues("spring.r2dbc.generate-unique-name:true").run((context) -> {
|
||||
assertThat(context).hasSingleBean(CityRepository.class);
|
||||
context.getBean(CityRepository.class).findById(2000L).as(StepVerifier::create).expectNextCount(1)
|
||||
.verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationWithNoRepositories() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.withUserConfiguration(EmptyConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(Repository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void honorsUsersEnableR2dbcRepositoriesConfiguration() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(R2dbcAutoConfiguration.class, R2dbcDataAutoConfiguration.class))
|
||||
.withUserConfiguration(DatabaseInitializationConfiguration.class, EnableRepositoriesConfiguration.class)
|
||||
.withPropertyValues("spring.r2dbc.generate-unique-name:true").run((context) -> {
|
||||
assertThat(context).hasSingleBean(CityRepository.class);
|
||||
context.getBean(CityRepository.class).findById(2000L).as(StepVerifier::create).expectNextCount(1)
|
||||
.verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class DatabaseInitializationConfiguration {
|
||||
|
||||
@Autowired
|
||||
void initializeDatabase(ConnectionFactory connectionFactory) {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class EmptyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableR2dbcRepositories(basePackageClasses = City.class)
|
||||
static class EnableRepositoriesConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.data.r2dbc;
|
||||
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
|
||||
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;
|
||||
import org.springframework.transaction.reactive.TransactionSynchronizationManager;
|
||||
import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link R2dbcTransactionManager}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
class R2dbcTransactionManagerAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(R2dbcTransactionManagerAutoConfiguration.class, TransactionAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void noTransactionManager() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveTransactionManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleTransactionManager() {
|
||||
this.contextRunner.withUserConfiguration(SingleConnectionFactoryConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(TransactionalOperator.class)
|
||||
.hasSingleBean(ReactiveTransactionManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void transactionManagerEnabled() {
|
||||
this.contextRunner.withUserConfiguration(SingleConnectionFactoryConfiguration.class, BaseConfiguration.class)
|
||||
.run((context) -> {
|
||||
TransactionalService bean = context.getBean(TransactionalService.class);
|
||||
bean.isTransactionActive().as(StepVerifier::create).expectNext(true).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SingleConnectionFactoryConfiguration {
|
||||
|
||||
@Bean
|
||||
ConnectionFactory connectionFactory() {
|
||||
ConnectionFactory connectionFactory = mock(ConnectionFactory.class);
|
||||
Connection connection = mock(Connection.class);
|
||||
given(connectionFactory.create()).willAnswer((invocation) -> Mono.just(connection));
|
||||
given(connection.beginTransaction()).willReturn(Mono.empty());
|
||||
given(connection.commitTransaction()).willReturn(Mono.empty());
|
||||
given(connection.close()).willReturn(Mono.empty());
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableTransactionManagement
|
||||
static class BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
TransactionalService transactionalService() {
|
||||
return new TransactionalServiceImpl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface TransactionalService {
|
||||
|
||||
@Transactional
|
||||
Mono<Boolean> isTransactionActive();
|
||||
|
||||
}
|
||||
|
||||
static class TransactionalServiceImpl implements TransactionalService {
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> isTransactionActive() {
|
||||
return TransactionSynchronizationManager.forCurrentTransaction()
|
||||
.map(TransactionSynchronizationManager::isActualTransactionActive);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.data.r2dbc.city;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
@Table("CITY")
|
||||
public class City {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String state;
|
||||
|
||||
private String country;
|
||||
|
||||
private String map;
|
||||
|
||||
protected City() {
|
||||
}
|
||||
|
||||
public City(String name, String country) {
|
||||
this.name = name;
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return this.country;
|
||||
}
|
||||
|
||||
public String getMap() {
|
||||
return this.map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName() + "," + getState() + "," + getCountry();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.data.r2dbc.city;
|
||||
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
|
||||
public interface CityRepository extends ReactiveCrudRepository<City, Long> {
|
||||
|
||||
}
|
||||
|
|
@ -1465,6 +1465,7 @@ bom {
|
|||
"spring-boot-starter-data-ldap",
|
||||
"spring-boot-starter-data-mongodb",
|
||||
"spring-boot-starter-data-mongodb-reactive",
|
||||
"spring-boot-starter-data-r2dbc",
|
||||
"spring-boot-starter-data-redis",
|
||||
"spring-boot-starter-data-redis-reactive",
|
||||
"spring-boot-starter-data-neo4j",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
plugins {
|
||||
id "org.springframework.boot.starter"
|
||||
}
|
||||
|
||||
description = "Starter for using Spring Data R2DBC"
|
||||
|
||||
dependencies {
|
||||
api(platform(project(":spring-boot-project:spring-boot-dependencies")))
|
||||
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter"))
|
||||
api("org.springframework.data:spring-data-r2dbc")
|
||||
api("io.r2dbc:r2dbc-spi")
|
||||
api("io.r2dbc:r2dbc-pool")
|
||||
}
|
||||
Loading…
Reference in New Issue