diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperations.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperations.java index 73cc729525..3ec79fd57b 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperations.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperations.java @@ -18,6 +18,10 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.data.jdbc.core.convert.DataAccessStrategy; +import org.springframework.data.jdbc.core.convert.JdbcConverter; +import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.lang.Nullable; /** @@ -29,6 +33,14 @@ */ public interface JdbcAggregateOperations { + RelationalMappingContext getRelationalMappingContext(); + + DataAccessStrategy getDataAccessStrategy(); + + JdbcConverter getJdbcConverter(); + + NamedParameterJdbcOperations getNamedParameterJdbcOperations(); + /** * Saves an instance of an aggregate, including all the members of the aggregate. * diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java index eab91a0d97..499b5bf4ce 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java @@ -39,6 +39,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.event.*; import org.springframework.data.support.PageableExecutionUtils; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -54,6 +55,7 @@ */ public class JdbcAggregateTemplate implements JdbcAggregateOperations { + private final ApplicationEventPublisher publisher; private final RelationalMappingContext context; @@ -62,8 +64,11 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { private final RelationalEntityUpdateWriter jdbcEntityUpdateWriter; private final DataAccessStrategy accessStrategy; + private final NamedParameterJdbcOperations operations; private final AggregateChangeExecutor executor; + private final JdbcConverter converter; + private EntityCallbacks entityCallbacks = EntityCallbacks.create(); /** @@ -76,7 +81,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { * @since 1.1 */ public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingContext context, JdbcConverter converter, - DataAccessStrategy dataAccessStrategy) { + DataAccessStrategy dataAccessStrategy, NamedParameterJdbcOperations operations) { Assert.notNull(publisher, "ApplicationContext must not be null!"); Assert.notNull(context, "RelationalMappingContext must not be null!"); @@ -85,7 +90,9 @@ public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingCont this.publisher = publisher; this.context = context; + this.converter = converter; this.accessStrategy = dataAccessStrategy; + this.operations = operations; this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context); this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context); @@ -105,7 +112,7 @@ public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingCont * @param dataAccessStrategy must not be {@literal null}. */ public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMappingContext context, - JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { + JdbcConverter converter, DataAccessStrategy dataAccessStrategy, NamedParameterJdbcOperations operations) { Assert.notNull(publisher, "ApplicationEventPublisher must not be null!"); Assert.notNull(context, "RelationalMappingContext must not be null!"); @@ -114,7 +121,9 @@ public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMapp this.publisher = publisher; this.context = context; + this.converter = converter; this.accessStrategy = dataAccessStrategy; + this.operations = operations; this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context); this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context); @@ -122,6 +131,22 @@ public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMapp this.executor = new AggregateChangeExecutor(converter, accessStrategy); } + public RelationalMappingContext getRelationalMappingContext() { + return context; + } + + public DataAccessStrategy getDataAccessStrategy() { + return accessStrategy; + } + + public NamedParameterJdbcOperations getNamedParameterJdbcOperations() { + return operations; + } + + public JdbcConverter getJdbcConverter() { + return converter; + } + /** * @param entityCallbacks * @since 1.1 diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java index 13ca2e865f..8d52125731 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java @@ -22,7 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; @@ -102,8 +101,7 @@ public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParam JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect ? ((JdbcDialect) dialect).getArraySupport() : JdbcArrayColumns.DefaultSupport.INSTANCE; - DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), - arrayColumns); + DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns); return new BasicJdbcConverter(mappingContext, relationResolver, conversions, jdbcTypeFactory, dialect.getIdentifierProcessing()); @@ -156,13 +154,15 @@ private List storeConverters(Dialect dialect) { * @param applicationContext for publishing events. Must not be {@literal null}. * @param mappingContext the mapping context to be used. Must not be {@literal null}. * @param converter the conversions used when reading and writing from/to the database. Must not be {@literal null}. + * @param operations the {@link NamedParameterJdbcOperations} allowing access to a {@link java.sql.Connection}. * @return a {@link JdbcAggregateTemplate}. Will never be {@literal null}. */ @Bean public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext, - JdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { + JdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy, + NamedParameterJdbcOperations operations) { - return new JdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy); + return new JdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy, operations); } /** diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java index dd60dd7dd6..bb9c3a5e56 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java @@ -28,7 +28,6 @@ import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean; import org.springframework.data.repository.config.DefaultRepositoryBaseClass; import org.springframework.jdbc.datasource.DataSourceTransactionManager; -import org.springframework.transaction.PlatformTransactionManager; /** * Annotation to enable JDBC repositories. Will scan the package of the annotated configuration class for Spring Data @@ -39,6 +38,7 @@ * @author Mark Paluch * @author Fei Dong * @author Antoine Sauray + * @author Tomohiko Ozawa * @see AbstractJdbcConfiguration */ @Target(ElementType.TYPE) @@ -131,4 +131,11 @@ */ String transactionManagerRef() default "transactionManager"; + /** + * Configures the name of the {@link org.springframework.data.jdbc.core.JdbcAggregateOperations} bean definition to be + * used to create repositories discovered through this annotation. + * + * @since 2.3 + */ + String jdbcAggregateOperationsRef() default ""; } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java index e201910a3c..2daa3a55a3 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java @@ -36,6 +36,7 @@ * @author Fei Dong * @author Mark Paluch * @author Antoine Sauray + * @author Tomohiko Ozawa */ public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport { @@ -85,6 +86,11 @@ public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSo Optional transactionManagerRef = source.getAttribute("transactionManagerRef"); builder.addPropertyValue("transactionManager", transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)); + + source.getAttribute("jdbcAggregateOperationsRef") + .filter(StringUtils::hasText) + .ifPresent(s -> builder.addPropertyReference("jdbcAggregateOperations", s)); + } /** diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java index 36558f64ba..98d4b723a8 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java @@ -19,10 +19,12 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.jdbc.core.JdbcAggregateOperations; import org.springframework.data.jdbc.core.JdbcAggregateTemplate; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; +import org.springframework.data.jdbc.repository.config.DialectResolver; import org.springframework.data.mapping.callback.EntityCallbacks; import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; @@ -89,6 +91,22 @@ public JdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy, RelationalMa this.operations = operations; } + /** + * Creates a new {@link JdbcRepositoryFactory} for the given {@link JdbcAggregateTemplate} and + * {@link ApplicationEventPublisher}. + * + * @param operations + * @param publisher + */ + public JdbcRepositoryFactory(JdbcAggregateOperations operations, ApplicationEventPublisher publisher) { + this.publisher = publisher; + this.context = operations.getRelationalMappingContext(); + this.converter = operations.getJdbcConverter(); + this.dialect = DialectResolver.getDialect(operations.getNamedParameterJdbcOperations().getJdbcOperations()); + this.accessStrategy = operations.getDataAccessStrategy(); + this.operations = operations.getNamedParameterJdbcOperations(); + } + /** * @param queryMappingConfiguration must not be {@literal null} consider {@link QueryMappingConfiguration#EMPTY} * instead. @@ -116,7 +134,8 @@ public EntityInformation getEntityInformation(Class aClass) { @Override protected Object getTargetRepository(RepositoryInformation repositoryInformation) { - JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, context, converter, accessStrategy); + JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, context, converter, accessStrategy, + operations); if (entityCallbacks != null) { template.setEntityCallbacks(entityCallbacks); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java index f52efa84e6..8250c5f445 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java @@ -21,6 +21,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.data.jdbc.core.JdbcAggregateOperations; +import org.springframework.data.jdbc.core.JdbcAggregateTemplate; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; @@ -58,6 +60,7 @@ public class JdbcRepositoryFactoryBean, S, ID extend private NamedParameterJdbcOperations operations; private EntityCallbacks entityCallbacks; private Dialect dialect; + private JdbcAggregateOperations jdbcAggregateOperations; /** * Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface. @@ -80,14 +83,22 @@ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } + public void setJdbcAggregateOperations(JdbcAggregateOperations jdbcAggregateOperations) { + this.jdbcAggregateOperations = jdbcAggregateOperations; + } + /** * Creates the actual {@link RepositoryFactorySupport} instance. */ @Override protected RepositoryFactorySupport doCreateRepositoryFactory() { - - JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext, - converter, dialect, publisher, operations); + JdbcRepositoryFactory jdbcRepositoryFactory; + if (jdbcAggregateOperations != null) { + jdbcRepositoryFactory = new JdbcRepositoryFactory(jdbcAggregateOperations, publisher); + } else { + jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext, + converter, dialect, publisher, operations); + } jdbcRepositoryFactory.setQueryMappingConfiguration(queryMappingConfiguration); jdbcRepositoryFactory.setEntityCallbacks(entityCallbacks); jdbcRepositoryFactory.setBeanFactory(beanFactory); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/ImmutableAggregateTemplateHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/ImmutableAggregateTemplateHsqlIntegrationTests.java index f5d8479bb5..9fdd48e548 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/ImmutableAggregateTemplateHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/ImmutableAggregateTemplateHsqlIntegrationTests.java @@ -22,24 +22,17 @@ import lombok.With; import org.assertj.core.api.SoftAssertions; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.annotation.Id; -import org.springframework.data.jdbc.core.convert.DataAccessStrategy; -import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.testing.TestConfiguration; -import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.junit4.rules.SpringClassRule; -import org.springframework.test.context.junit4.rules.SpringMethodRule; import org.springframework.transaction.annotation.Transactional; /** @@ -325,11 +318,5 @@ static class Config { Class testClass() { return ImmutableAggregateTemplateHsqlIntegrationTests.class; } - - @Bean - JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context, - DataAccessStrategy dataAccessStrategy, JdbcConverter converter) { - return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy); - } } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java index 52d848a8f0..3b24c6106c 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java @@ -42,7 +42,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -53,15 +52,12 @@ import org.springframework.data.annotation.Version; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import org.springframework.data.jdbc.core.convert.DataAccessStrategy; -import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.testing.AssumeFeatureTestExecutionListener; import org.springframework.data.jdbc.testing.EnabledOnFeature; import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.jdbc.testing.TestDatabaseFeatures; import org.springframework.data.relational.core.conversion.DbActionExecutionException; import org.springframework.data.relational.core.mapping.Column; -import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.Table; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.test.context.ContextConfiguration; @@ -1262,11 +1258,5 @@ static class Config { Class testClass() { return JdbcAggregateTemplateIntegrationTests.class; } - - @Bean - JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context, - DataAccessStrategy dataAccessStrategy, JdbcConverter converter) { - return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy); - } } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java index f0b41ca4ec..2461fc8f12 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java @@ -22,18 +22,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.annotation.Id; -import org.springframework.data.jdbc.core.convert.DataAccessStrategy; -import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.testing.AssumeFeatureTestExecutionListener; import org.springframework.data.jdbc.testing.EnabledOnFeature; import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.relational.core.mapping.NamingStrategy; -import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -96,12 +92,6 @@ Class testClass() { return JdbcAggregateTemplateSchemaIntegrationTests.class; } - @Bean - JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context, - DataAccessStrategy dataAccessStrategy, JdbcConverter converter) { - return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy); - } - @Bean NamingStrategy namingStrategy() { return new NamingStrategy() { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java index 2362db6243..53236581f7 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java @@ -48,6 +48,7 @@ import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback; import org.springframework.data.relational.core.mapping.event.BeforeDeleteCallback; import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; /** * Unit tests for {@link JdbcAggregateTemplate}. @@ -65,6 +66,7 @@ public class JdbcAggregateTemplateUnitTests { @Mock ApplicationEventPublisher eventPublisher; @Mock RelationResolver relationResolver; @Mock EntityCallbacks callbacks; + @Mock NamedParameterJdbcOperations operations; @BeforeEach public void setUp() { @@ -72,7 +74,7 @@ public void setUp() { RelationalMappingContext mappingContext = new RelationalMappingContext(NamingStrategy.INSTANCE); JdbcConverter converter = new BasicJdbcConverter(mappingContext, relationResolver); - template = new JdbcAggregateTemplate(eventPublisher, mappingContext, converter, dataAccessStrategy); + template = new JdbcAggregateTemplate(eventPublisher, mappingContext, converter, dataAccessStrategy, operations); ((JdbcAggregateTemplate) template).setEntityCallbacks(callbacks); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java index 6cc7918060..c97b3586df 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java @@ -30,14 +30,21 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Lazy; import org.springframework.data.annotation.Id; +import org.springframework.data.jdbc.core.JdbcAggregateOperations; import org.springframework.data.jdbc.core.JdbcAggregateTemplate; +import org.springframework.data.jdbc.core.convert.BasicJdbcConverter; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy; +import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory; import org.springframework.data.jdbc.core.convert.JdbcConverter; +import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; +import org.springframework.data.jdbc.core.convert.RelationResolver; import org.springframework.data.jdbc.core.convert.SqlGeneratorSource; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositoriesIntegrationTests.TestConfiguration; @@ -60,6 +67,7 @@ * @author Greg Turnquist * @author Evgeni Dimitrov * @author Fei Dong + * @author Tomohiko Ozawa */ @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfiguration.class) @@ -70,6 +78,8 @@ public class EnableJdbcRepositoriesIntegrationTests { static final Field OPERATIONS = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "operations"); static final Field DATA_ACCESS_STRATEGY = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "dataAccessStrategy"); + static final Field AGGREGATE_OPERATIONS = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, + "jdbcAggregateOperations"); public static final RowMapper DUMMY_ENTITY_ROW_MAPPER = mock(RowMapper.class); public static final RowMapper STRING_ROW_MAPPER = mock(RowMapper.class); @@ -77,8 +87,10 @@ public class EnableJdbcRepositoriesIntegrationTests { @Autowired DummyRepository repository; @Autowired @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations defaultOperations; @Autowired @Qualifier("defaultDataAccessStrategy") DataAccessStrategy defaultDataAccessStrategy; + @Autowired @Qualifier("jdbcAggregateOperations") JdbcAggregateOperations defaultJdbcAggregateOperations; @Autowired @Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations qualifierJdbcOperations; @Autowired @Qualifier("qualifierDataAccessStrategy") DataAccessStrategy qualifierDataAccessStrategy; + @Autowired @Qualifier("qualifierJdbcAggregateOperations") JdbcAggregateOperations qualifierJdbcAggregateOperations; @BeforeAll public static void setup() { @@ -86,6 +98,7 @@ public static void setup() { MAPPER_MAP.setAccessible(true); OPERATIONS.setAccessible(true); DATA_ACCESS_STRATEGY.setAccessible(true); + AGGREGATE_OPERATIONS.setAccessible(true); } @Test // DATAJDBC-100 @@ -118,6 +131,10 @@ public void jdbcOperationsRef() { DataAccessStrategy dataAccessStrategy = (DataAccessStrategy) ReflectionUtils.getField(DATA_ACCESS_STRATEGY, factoryBean); assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy); + + JdbcAggregateTemplate aggregateTemplate = (JdbcAggregateTemplate) ReflectionUtils.getField(AGGREGATE_OPERATIONS, + factoryBean); + assertThat(aggregateTemplate).isNotSameAs(defaultJdbcAggregateOperations).isSameAs(qualifierJdbcAggregateOperations); } interface DummyRepository extends CrudRepository { @@ -133,7 +150,7 @@ static class DummyEntity { @EnableJdbcRepositories(considerNestedRepositories = true, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DummyRepository.class), jdbcOperationsRef = "qualifierJdbcOperations", dataAccessStrategyRef = "qualifierDataAccessStrategy", - repositoryBaseClass = DummyRepositoryBaseClass.class) + jdbcAggregateOperationsRef = "qualifierJdbcAggregateOperations", repositoryBaseClass = DummyRepositoryBaseClass.class) static class TestConfiguration { @Bean @@ -166,6 +183,27 @@ DataAccessStrategy defaultDataAccessStrategy( Dialect jdbcDialect(@Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations operations) { return DialectResolver.getDialect(operations.getJdbcOperations()); } + + @Bean("qualifierJdbcAggregateOperations") + public JdbcAggregateOperations jdbcAggregateOperations(ApplicationContext applicationContext, + @Lazy RelationResolver relationResolver, + @Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations operations) { + + RelationalMappingContext relationalMappingContext = new RelationalMappingContext(); + Dialect dialect = DialectResolver.getDialect(operations.getJdbcOperations()); + + JdbcConverter jdbcConverter = new BasicJdbcConverter(new RelationalMappingContext(), relationResolver, + new JdbcCustomConversions(), new DefaultJdbcTypeFactory(operations.getJdbcOperations()), + dialect.getIdentifierProcessing()); + + DataAccessStrategy dataAccessStrategy = new DefaultDataAccessStrategy( + new SqlGeneratorSource(relationalMappingContext, jdbcConverter, + DialectResolver.getDialect(operations.getJdbcOperations())), + relationalMappingContext, jdbcConverter, operations); + + return new JdbcAggregateTemplate(applicationContext, relationalMappingContext, jdbcConverter, dataAccessStrategy, + operations); + } } private static class DummyRepositoryBaseClass implements CrudRepository { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java index c1804f217c..af5ecbe144 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java @@ -23,16 +23,18 @@ import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; - import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.data.convert.CustomConversions; +import org.springframework.data.jdbc.core.JdbcAggregateOperations; +import org.springframework.data.jdbc.core.JdbcAggregateTemplate; import org.springframework.data.jdbc.core.convert.BasicJdbcConverter; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy; @@ -66,6 +68,7 @@ * @author Fei Dong * @author Myeonghyeon Lee * @author Christoph Strobl + * @author Tomohiko Ozawa */ @Configuration @ComponentScan // To pick up configuration classes (per activated profile) @@ -135,7 +138,7 @@ private List storeConverters(Dialect dialect) { } @Bean - JdbcConverter relationalConverter(RelationalMappingContext mappingContext, @Lazy RelationResolver relationResolver, + JdbcConverter converter(RelationalMappingContext mappingContext, @Lazy RelationResolver relationResolver, CustomConversions conversions, @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, Dialect dialect) { @@ -160,4 +163,17 @@ Dialect jdbcDialect(NamedParameterJdbcOperations operations) { TestDatabaseFeatures features(NamedParameterJdbcOperations operations) { return new TestDatabaseFeatures(operations.getJdbcOperations()); } + + @Bean JdbcAggregateOperations jdbcAggregateOperations( + ApplicationContext applicationContext, + @Qualifier("converter") JdbcConverter jdbcConverter, + @Qualifier("defaultDataAccessStrategy") DataAccessStrategy dataAccessStrategy, + @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations operations) { + return new JdbcAggregateTemplate( + applicationContext, + new RelationalMappingContext(), + jdbcConverter, + dataAccessStrategy, + operations); + } }