diff --git a/src/main/java/org/springframework/data/r2dbc/repository/config/AbstractR2dbcConfiguration.java b/src/main/java/org/springframework/data/r2dbc/repository/config/AbstractR2dbcConfiguration.java new file mode 100644 index 0000000..7e5be5b --- /dev/null +++ b/src/main/java/org/springframework/data/r2dbc/repository/config/AbstractR2dbcConfiguration.java @@ -0,0 +1,84 @@ +package org.springframework.data.r2dbc.repository.config; + +import io.r2dbc.spi.ConnectionFactory; + +import java.util.Optional; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.r2dbc.function.DatabaseClient; +import org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy; +import org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy; +import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator; +import org.springframework.data.r2dbc.support.SqlErrorCodeR2dbcExceptionTranslator; +import org.springframework.data.relational.core.conversion.BasicRelationalConverter; +import org.springframework.data.relational.core.mapping.NamingStrategy; +import org.springframework.data.relational.core.mapping.RelationalMappingContext; + +/** + * Base class for Spring Data R2DBC configuration containing bean declarations that must be registered for Spring Data + * R2DBC to work. + * + * @author Mark Paluch + * @see ConnectionFactory + * @see DatabaseClient + * @see EnableR2dbcRepositories + */ +@Configuration +public abstract class AbstractR2dbcConfiguration { + + /** + * Return a R2DBC {@link ConnectionFactory}. Annotate with {@link Bean} in case you want to expose a + * {@link ConnectionFactory} instance to the {@link org.springframework.context.ApplicationContext}. + * + * @return the configured {@link ConnectionFactory}. + */ + public abstract ConnectionFactory connectionFactory(); + + /** + * Register a {@link DatabaseClient} using {@link #connectionFactory()} and {@link RelationalMappingContext}. + * + * @return must not be {@literal null}. + */ + @Bean + public DatabaseClient databaseClient(ReactiveDataAccessStrategy dataAccessStrategy, + R2dbcExceptionTranslator exceptionTranslator) { + + return DatabaseClient.builder().connectionFactory(connectionFactory()).dataAccessStrategy(dataAccessStrategy) + .exceptionTranslator(exceptionTranslator).build(); + } + + /** + * Register a {@link RelationalMappingContext} and apply an optional {@link NamingStrategy}. + * + * @param namingStrategy optional {@link NamingStrategy}. Use {@link NamingStrategy#INSTANCE} as fallback. + * @return must not be {@literal null}. + */ + @Bean + public RelationalMappingContext r2dbcMappingContext(Optional namingStrategy) { + return new RelationalMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE)); + } + + /** + * Creates a {@link ReactiveDataAccessStrategy} using the configured {@link #r2dbcMappingContext(Optional)}. + * + * @param mappingContext the configured {@link RelationalMappingContext}. + * @return must not be {@literal null}. + * @see #r2dbcMappingContext(Optional) + */ + @Bean + public ReactiveDataAccessStrategy reactiveDataAccessStrategy(RelationalMappingContext mappingContext) { + return new DefaultReactiveDataAccessStrategy(new BasicRelationalConverter(mappingContext)); + } + + /** + * Creates a {@link R2dbcExceptionTranslator} using the configured {@link #connectionFactory()}. + * + * @return must not be {@literal null}. + * @see #connectionFactory() + */ + @Bean + public R2dbcExceptionTranslator exceptionTranslator() { + return new SqlErrorCodeR2dbcExceptionTranslator(connectionFactory()); + } +} diff --git a/src/test/java/org/springframework/data/r2dbc/repository/R2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/R2dbcRepositoryIntegrationTests.java index fc2fcb1..aa33cd8 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/R2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/R2dbcRepositoryIntegrationTests.java @@ -32,10 +32,16 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; import org.springframework.data.annotation.Id; -import org.springframework.data.r2dbc.function.DatabaseClient; import org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy; import org.springframework.data.r2dbc.function.TransactionalDatabaseClient; +import org.springframework.data.r2dbc.repository.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.repository.query.Query; import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory; import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport; @@ -44,31 +50,39 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; /** * Integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory}. * * @author Mark Paluch */ +@RunWith(SpringRunner.class) +@ContextConfiguration public class R2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport { private static RelationalMappingContext mappingContext = new RelationalMappingContext(); - private ConnectionFactory connectionFactory; - private DatabaseClient databaseClient; - private LegoSetRepository repository; + @Autowired private LegoSetRepository repository; private JdbcTemplate jdbc; + @Configuration + @EnableR2dbcRepositories(considerNestedRepositories = true, + includeFilters = @Filter(classes = LegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE)) + static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration { + + @Override + public ConnectionFactory connectionFactory() { + return createConnectionFactory(); + } + } + @Before public void before() { Hooks.onOperatorDebug(); - this.connectionFactory = createConnectionFactory(); - this.databaseClient = DatabaseClient.builder().connectionFactory(connectionFactory) - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(new BasicRelationalConverter(mappingContext))) - .build(); - this.jdbc = createJdbcTemplate(createDataSource()); String tableToCreate = "CREATE TABLE IF NOT EXISTS repo_legoset (\n" + " id SERIAL PRIMARY KEY,\n" @@ -76,8 +90,6 @@ public class R2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport this.jdbc.execute("DROP TABLE IF EXISTS repo_legoset"); this.jdbc.execute(tableToCreate); - - this.repository = new R2dbcRepositoryFactory(databaseClient, mappingContext).getRepository(LegoSetRepository.class); } @Test @@ -136,7 +148,8 @@ public class R2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport @Test public void shouldInsertItemsTransactional() { - TransactionalDatabaseClient client = TransactionalDatabaseClient.builder().connectionFactory(connectionFactory) + TransactionalDatabaseClient client = TransactionalDatabaseClient.builder() + .connectionFactory(createConnectionFactory()) .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(new BasicRelationalConverter(mappingContext))) .build(); diff --git a/src/test/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepositoryIntegrationTests.java index fe60a1e..14c4884 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepositoryIntegrationTests.java @@ -17,20 +17,28 @@ package org.springframework.data.r2dbc.repository.support; import static org.assertj.core.api.Assertions.*; -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; - import io.r2dbc.spi.ConnectionFactory; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Hooks; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.function.DatabaseClient; -import org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy; import org.springframework.data.r2dbc.function.convert.MappingR2dbcConverter; +import org.springframework.data.r2dbc.repository.config.AbstractR2dbcConfiguration; import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport; import org.springframework.data.relational.core.conversion.BasicRelationalConverter; import org.springframework.data.relational.core.mapping.RelationalMappingContext; @@ -39,35 +47,39 @@ import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.relational.repository.query.RelationalEntityInformation; import org.springframework.data.relational.repository.support.MappingRelationalEntityInformation; import org.springframework.jdbc.core.JdbcTemplate; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Hooks; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; /** * Integration tests for {@link SimpleR2dbcRepository}. * * @author Mark Paluch */ +@RunWith(SpringRunner.class) +@ContextConfiguration public class SimpleR2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport { - private static RelationalMappingContext mappingContext = new RelationalMappingContext(); + @Autowired private DatabaseClient databaseClient; + + @Autowired private RelationalMappingContext mappingContext; - private ConnectionFactory connectionFactory; - private DatabaseClient databaseClient; private SimpleR2dbcRepository repository; private JdbcTemplate jdbc; + @Configuration + static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration { + + @Override + public ConnectionFactory connectionFactory() { + return createConnectionFactory(); + } + } + @Before public void before() { Hooks.onOperatorDebug(); - this.connectionFactory = createConnectionFactory(); - this.databaseClient = DatabaseClient.builder().connectionFactory(connectionFactory) - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(new BasicRelationalConverter(mappingContext))) - .build(); - RelationalEntityInformation entityInformation = new MappingRelationalEntityInformation<>( (RelationalPersistentEntity) mappingContext.getRequiredPersistentEntity(LegoSet.class));