From b4002e5c3f6dc1bfb27daaf2b98b65015a30f4f2 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 3 Sep 2020 11:07:27 +0200 Subject: [PATCH] #440 - Create R2dbcEntityTemplate in R2dbcRepositoryFactoryBean. We now create R2dbcEntityTemplate as part of R2dbcRepositoryFactoryBean initialization if the factory bean was configured with DatabaseClient and DataAccessStrategy only. Creating the template in the factory bean allows collecting entity callbacks for repository usage. --- .../support/R2dbcRepositoryFactory.java | 5 +++- .../support/R2dbcRepositoryFactoryBean.java | 24 ++++++++++++++++++- ...stractR2dbcRepositoryIntegrationTests.java | 1 + ...stgresR2dbcRepositoryIntegrationTests.java | 21 +++++++++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java b/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java index f1381b0e..f3bbb00b 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java @@ -60,6 +60,7 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport { private final ReactiveDataAccessStrategy dataAccessStrategy; private final MappingContext, ? extends RelationalPersistentProperty> mappingContext; private final R2dbcConverter converter; + private final R2dbcEntityOperations operations; /** * Creates a new {@link R2dbcRepositoryFactory} given {@link DatabaseClient} and {@link MappingContext}. @@ -76,6 +77,7 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport { this.dataAccessStrategy = dataAccessStrategy; this.converter = dataAccessStrategy.getConverter(); this.mappingContext = this.converter.getMappingContext(); + this.operations = new R2dbcEntityTemplate(this.databaseClient, this.dataAccessStrategy); setEvaluationContextProvider(ReactiveQueryMethodEvaluationContextProvider.DEFAULT); } @@ -93,6 +95,7 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport { this.dataAccessStrategy = operations.getDataAccessStrategy(); this.converter = dataAccessStrategy.getConverter(); this.mappingContext = this.converter.getMappingContext(); + this.operations = operations; setEvaluationContextProvider(ReactiveQueryMethodEvaluationContextProvider.DEFAULT); } @@ -116,7 +119,7 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport { information); return getTargetRepositoryViaReflection(information, entityInformation, - new R2dbcEntityTemplate(this.databaseClient, this.dataAccessStrategy), this.converter); + operations, this.converter); } /* diff --git a/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryBean.java b/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryBean.java index 3ec5db2b..bf1969e9 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryBean.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryBean.java @@ -17,8 +17,12 @@ package org.springframework.data.r2dbc.repository.support; import java.io.Serializable; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.r2dbc.core.R2dbcEntityOperations; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; @@ -38,11 +42,12 @@ import org.springframework.util.Assert; * @see org.springframework.data.repository.reactive.ReactiveSortingRepository */ public class R2dbcRepositoryFactoryBean, S, ID extends Serializable> - extends RepositoryFactoryBeanSupport { + extends RepositoryFactoryBeanSupport implements ApplicationContextAware { private @Nullable DatabaseClient client; private @Nullable ReactiveDataAccessStrategy dataAccessStrategy; private @Nullable R2dbcEntityOperations operations; + private @Nullable ApplicationContext applicationContext; private boolean mappingContextConfigured = false; @@ -122,6 +127,15 @@ public class R2dbcRepositoryFactoryBean, S, ID exten return new R2dbcRepositoryFactory(operations); } + /* + * (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + /* * (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() @@ -134,6 +148,14 @@ public class R2dbcRepositoryFactoryBean, S, ID exten Assert.state(client != null, "DatabaseClient must not be null when R2dbcEntityOperations is not configured!"); Assert.state(dataAccessStrategy != null, "ReactiveDataAccessStrategy must not be null when R2dbcEntityOperations is not configured!"); + + R2dbcEntityTemplate template = new R2dbcEntityTemplate(client, dataAccessStrategy); + + if (applicationContext != null) { + template.setApplicationContext(applicationContext); + } + + operations = template; } else { dataAccessStrategy = operations.getDataAccessStrategy(); } diff --git a/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java index 0a09b899..2955b7f7 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java @@ -366,6 +366,7 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg @AllArgsConstructor @NoArgsConstructor @Getter + @Setter static class Lego { @Id Integer id; } diff --git a/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java index cc4b500b..dec3031b 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/PostgresR2dbcRepositoryIntegrationTests.java @@ -37,12 +37,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.mapping.event.BeforeConvertCallback; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory; import org.springframework.data.r2dbc.testing.ExternalDatabase; import org.springframework.data.r2dbc.testing.PostgresTestSupport; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; @@ -70,6 +72,23 @@ public class PostgresR2dbcRepositoryIntegrationTests extends AbstractR2dbcReposi public ConnectionFactory connectionFactory() { return PostgresTestSupport.createConnectionFactory(database); } + + @Bean + public BeforeConvertCallback autogeneratedId(DatabaseClient client) { + + return (entity, table) -> { + + if (entity.getId() == null) { + return client.sql("SELECT nextval('person_seq');") // + .map(row -> row.get(0, Integer.class)) // + .first() // + .doOnNext(entity::setId) // + .thenReturn(entity); + } + + return Mono.just(entity); + }; + } } @Override @@ -84,7 +103,7 @@ public class PostgresR2dbcRepositoryIntegrationTests extends AbstractR2dbcReposi @Override protected String getCreateTableStatement() { - return PostgresTestSupport.CREATE_TABLE_LEGOSET_WITH_ID_GENERATION; + return PostgresTestSupport.CREATE_TABLE_LEGOSET + ";CREATE SEQUENCE IF NOT EXISTS person_seq;"; } @Override