From 932d9ce925cde0931b8d176533408bc8a8a2d72d Mon Sep 17 00:00:00 2001 From: Tomohiko Ozawa Date: Mon, 25 Dec 2023 03:52:35 +0900 Subject: [PATCH 1/3] add `jdbcAggregateOperationsRef` to `@EnableJdbcRepositories` --- .../jdbc/core/JdbcAggregateOperations.java | 17 +++++++ .../data/jdbc/core/JdbcAggregateTemplate.java | 33 ++++++++----- .../config => dialect}/DialectResolver.java | 2 +- .../config/AbstractJdbcConfiguration.java | 39 +++++++-------- .../config/EnableJdbcRepositories.java | 8 ++++ .../config/JdbcRepositoryConfigExtension.java | 13 +++-- .../support/JdbcRepositoryFactory.java | 19 +++++++- .../support/JdbcRepositoryFactoryBean.java | 48 ++++++++++++------- .../main/resources/META-INF/spring.factories | 2 +- ...JdbcAggregateTemplateIntegrationTests.java | 28 ++--------- ...AggregateTemplateHsqlIntegrationTests.java | 10 ---- ...gregateTemplateSchemaIntegrationTests.java | 12 ----- .../core/JdbcAggregateTemplateUnitTests.java | 2 +- ...nableJdbcRepositoriesIntegrationTests.java | 35 +++++++++++++- .../JdbcRepositoryFactoryBeanUnitTests.java | 12 ++++- .../data/jdbc/testing/TestConfiguration.java | 11 ++++- 16 files changed, 181 insertions(+), 110 deletions(-) rename spring-data-jdbc/src/main/java/org/springframework/data/jdbc/{repository/config => dialect}/DialectResolver.java (99%) 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 f7e7af35f2..effc00071f 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 @@ -22,6 +22,8 @@ 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.query.Query; import org.springframework.lang.Nullable; @@ -34,6 +36,7 @@ * @author Chirag Tailor * @author Diego Krupitza * @author Myeonghyeon Lee + * @author Tomohiko Ozawa */ public interface JdbcAggregateOperations { @@ -312,4 +315,18 @@ default void delete(T aggregateRoot, Class domainType) { default void deleteAll(Iterable aggregateRoots, Class domainType) { deleteAll(aggregateRoots); } + + /** + * Returns the {@link JdbcConverter}. + * + * @return the {@link JdbcConverter}. + */ + JdbcConverter getConverter(); + + /** + * Return the {@link DataAccessStrategy} + * + * @return the {@link DataAccessStrategy} + */ + DataAccessStrategy getDataAccessStrategy(); } 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 efa04a8d8b..807fef93fc 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 @@ -67,6 +67,7 @@ * @author Myeonghyeon Lee * @author Chirag Tailor * @author Diego Krupitza + * @author Tomohiko Ozawa */ public class JdbcAggregateTemplate implements JdbcAggregateOperations { @@ -86,22 +87,20 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { * {@link DataAccessStrategy}. * * @param publisher must not be {@literal null}. - * @param context must not be {@literal null}. * @param dataAccessStrategy must not be {@literal null}. * @since 1.1 */ - public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingContext context, JdbcConverter converter, + public JdbcAggregateTemplate(ApplicationContext publisher, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { Assert.notNull(publisher, "ApplicationContext must not be null"); - Assert.notNull(context, "RelationalMappingContext must not be null"); Assert.notNull(converter, "RelationalConverter must not be null"); Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null"); this.eventDelegate.setPublisher(publisher); - this.context = context; - this.accessStrategy = dataAccessStrategy; this.converter = converter; + this.accessStrategy = dataAccessStrategy; + this.context = converter.getMappingContext(); this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context); @@ -115,21 +114,19 @@ public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingCont * {@link RelationalMappingContext} and {@link DataAccessStrategy}. * * @param publisher must not be {@literal null}. - * @param context must not be {@literal null}. * @param dataAccessStrategy must not be {@literal null}. */ - public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMappingContext context, - JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { + public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcConverter converter, + DataAccessStrategy dataAccessStrategy) { Assert.notNull(publisher, "ApplicationEventPublisher must not be null"); - Assert.notNull(context, "RelationalMappingContext must not be null"); Assert.notNull(converter, "RelationalConverter must not be null"); Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null"); this.eventDelegate.setPublisher(publisher); - this.context = context; - this.accessStrategy = dataAccessStrategy; this.converter = converter; + this.accessStrategy = dataAccessStrategy; + this.context = converter.getMappingContext(); this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context); this.executor = new AggregateChangeExecutor(converter, accessStrategy); @@ -656,9 +653,19 @@ private T triggerBeforeDelete(@Nullable T aggregateRoot, Object id, MutableA return null; } - private record EntityAndPreviousVersion (T entity, @Nullable Number version) { + private record EntityAndPreviousVersion(T entity, @Nullable Number version) { } - private record EntityAndChangeCreator (T entity, Function> changeCreator) { + private record EntityAndChangeCreator(T entity, Function> changeCreator) { + } + + @Override + public DataAccessStrategy getDataAccessStrategy() { + return accessStrategy; + } + + @Override + public JdbcConverter getConverter() { + return converter; } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/dialect/DialectResolver.java similarity index 99% rename from spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java rename to spring-data-jdbc/src/main/java/org/springframework/data/jdbc/dialect/DialectResolver.java index c55240754b..6ecc3e1ba1 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/dialect/DialectResolver.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.jdbc.repository.config; +package org.springframework.data.jdbc.dialect; import java.sql.Connection; import java.sql.DatabaseMetaData; 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 bd725b98d3..2d87f8ab68 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 @@ -26,7 +26,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; @@ -40,6 +39,7 @@ import org.springframework.data.jdbc.core.dialect.JdbcDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; +import org.springframework.data.jdbc.dialect.DialectResolver; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.RelationalManagedTypes; import org.springframework.data.relational.core.conversion.RelationalConverter; @@ -61,6 +61,7 @@ * @author Christoph Strobl * @author Myeonghyeon Lee * @author Chirag Tailor + * @author Tomohiko Ozawa * @since 1.1 */ @Configuration(proxyBeanMethods = false) @@ -103,7 +104,7 @@ public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException { * * @param namingStrategy optional {@link NamingStrategy}. Use * {@link org.springframework.data.relational.core.mapping.DefaultNamingStrategy#INSTANCE} as fallback. - * @param customConversions see {@link #jdbcCustomConversions()}. + * @param customConversions see {@link #jdbcCustomConversions(Optional)}. * @param jdbcManagedTypes JDBC managed types, typically discovered through {@link #jdbcManagedTypes() an entity * scan}. * @return must not be {@literal null}. @@ -124,7 +125,7 @@ public JdbcMappingContext jdbcMappingContext(Optional namingStra * {@link #jdbcMappingContext(Optional, JdbcCustomConversions, RelationalManagedTypes)}. * * @see #jdbcMappingContext(Optional, JdbcCustomConversions, RelationalManagedTypes) - * @see #jdbcCustomConversions() + * @see #jdbcCustomConversions(Optional) * @return must not be {@literal null}. */ @Bean @@ -147,23 +148,17 @@ public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParam * @return will never be {@literal null}. */ @Bean - public JdbcCustomConversions jdbcCustomConversions() { - - try { - - Dialect dialect = applicationContext.getBean(Dialect.class); - SimpleTypeHolder simpleTypeHolder = dialect.simpleTypes().isEmpty() ? JdbcSimpleTypes.HOLDER - : new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); - - return new JdbcCustomConversions( - CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), userConverters()); - - } catch (NoSuchBeanDefinitionException exception) { - + public JdbcCustomConversions jdbcCustomConversions(Optional dialect) { + return dialect.map(d -> { + SimpleTypeHolder simpleTypeHolder = d.simpleTypes().isEmpty() + ? JdbcSimpleTypes.HOLDER + : new SimpleTypeHolder(d.simpleTypes(), JdbcSimpleTypes.HOLDER); + return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(d)), + userConverters()); + }).orElseGet(() -> { LOG.warn("No dialect found; CustomConversions will be configured without dialect specific conversions"); - return new JdbcCustomConversions(); - } + }); } protected List userConverters() { @@ -191,7 +186,7 @@ private List storeConverters(Dialect dialect) { public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext, JdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { - return new JdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy); + return new JdbcAggregateTemplate(applicationContext, converter, dataAccessStrategy); } /** @@ -207,8 +202,7 @@ public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations op SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context, jdbcConverter, dialect); DataAccessStrategyFactory factory = new DataAccessStrategyFactory(sqlGeneratorSource, jdbcConverter, operations, - new SqlParametersFactory(context, jdbcConverter), - new InsertStrategyFactory(operations, dialect)); + new SqlParametersFactory(context, jdbcConverter), new InsertStrategyFactory(operations, dialect)); return factory.create(); } @@ -219,8 +213,7 @@ public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations op * @param operations the {@link NamedParameterJdbcOperations} allowing access to a {@link java.sql.Connection}. * @return the {@link Dialect} to be used. * @since 2.0 - * @throws org.springframework.data.jdbc.repository.config.DialectResolver.NoDialectException if the {@link Dialect} - * cannot be determined. + * @throws DialectResolver.NoDialectException if the {@link Dialect} cannot be determined. */ @Bean public Dialect jdbcDialect(NamedParameterJdbcOperations 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 f250e84f37..25bb882ecb 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 @@ -122,7 +122,9 @@ /** * Configures the name of the {@link org.springframework.data.jdbc.core.convert.DataAccessStrategy} bean definition to * be used to create repositories discovered through this annotation. Defaults to {@code defaultDataAccessStrategy}. + * @deprecated since 3.3 use {@link #jdbcAggregateOperationsRef()} instead */ + @Deprecated(since = "3.3") String dataAccessStrategyRef() default ""; /** @@ -133,6 +135,12 @@ */ String transactionManagerRef() default "transactionManager"; + /** + * Configure the name of the {@link org.springframework.data.jdbc.core.JdbcAggregateOperations} bean definition to be + * used to create repositories discovered through this annotation. + */ + String jdbcAggregateOperationsRef() default ""; + /** * Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to * {@link QueryLookupStrategy.Key#CREATE_IF_NOT_FOUND}. 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 19535f2568..3d825a9602 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 @@ -40,6 +40,7 @@ * @author Fei Dong * @author Mark Paluch * @author Antoine Sauray + * @author Tomohiko Ozawa */ public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport { @@ -79,9 +80,15 @@ public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSo Optional transactionManagerRef = source.getAttribute("transactionManagerRef"); builder.addPropertyValue("transactionManager", transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)); - builder.addPropertyValue("mappingContext", new RuntimeBeanReference(JdbcMappingContext.class)); - builder.addPropertyValue("dialect", new RuntimeBeanReference(Dialect.class)); - builder.addPropertyValue("converter", new RuntimeBeanReference(JdbcConverter.class)); + Optional jdbcAggregateOperationsRef = source.getAttribute("jdbcAggregateOperationsRef"); + + if (jdbcAggregateOperationsRef.isPresent()) { + builder.addPropertyReference("jdbcAggregateOperations", jdbcAggregateOperationsRef.get()); + } else { + builder.addPropertyValue("mappingContext", new RuntimeBeanReference(JdbcMappingContext.class)); + builder.addPropertyValue("dialect", new RuntimeBeanReference(Dialect.class)); + builder.addPropertyValue("converter", new RuntimeBeanReference(JdbcConverter.class)); + } } /** 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 f6becf1ff6..42b6c98a94 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,9 +19,11 @@ 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.dialect.DialectResolver; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.mapping.callback.EntityCallbacks; import org.springframework.data.relational.core.dialect.Dialect; @@ -48,6 +50,7 @@ * @author Hebert Coelho * @author Diego Krupitza * @author Christopher Klein + * @author Tomohiko Ozawa */ public class JdbcRepositoryFactory extends RepositoryFactorySupport { @@ -62,6 +65,20 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport { private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY; private EntityCallbacks entityCallbacks; + public JdbcRepositoryFactory(ApplicationEventPublisher publisher, JdbcAggregateOperations jdbcAggregateOperations, + NamedParameterJdbcOperations operations) { + Assert.notNull(publisher, "ApplicationEventPublisher must not be null"); + Assert.notNull(jdbcAggregateOperations, "JdbcAggregateOperations must not be null"); + Assert.notNull(operations, "NamedParameterJdbcOperations must not be null"); + + this.converter = jdbcAggregateOperations.getConverter(); + this.accessStrategy = jdbcAggregateOperations.getDataAccessStrategy(); + this.context = jdbcAggregateOperations.getConverter().getMappingContext(); + this.dialect = DialectResolver.getDialect(operations.getJdbcOperations()); + this.operations = operations; + this.publisher = publisher; + } + /** * Creates a new {@link JdbcRepositoryFactory} for the given {@link DataAccessStrategy}, * {@link RelationalMappingContext} and {@link ApplicationEventPublisher}. @@ -114,7 +131,7 @@ public EntityInformation getEntityInformation(Class aClass) { @Override protected Object getTargetRepository(RepositoryInformation repositoryInformation) { - JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, context, converter, accessStrategy); + JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, converter, accessStrategy); 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 a76db20a13..b975ec413d 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.DataAccessStrategyFactory; import org.springframework.data.jdbc.core.convert.InsertStrategyFactory; @@ -48,6 +50,7 @@ * @author Mark Paluch * @author Hebert Coelho * @author Chirag Tailor + * @author Tomohiko Ozawa */ public class JdbcRepositoryFactoryBean, S, ID extends Serializable> extends TransactionalRepositoryFactoryBeanSupport implements ApplicationEventPublisherAware { @@ -59,6 +62,7 @@ public class JdbcRepositoryFactoryBean, S, ID extend private DataAccessStrategy dataAccessStrategy; private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY; private NamedParameterJdbcOperations operations; + private JdbcAggregateOperations aggregateOperations; private EntityCallbacks entityCallbacks; private Dialect dialect; @@ -85,8 +89,7 @@ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { @Override protected RepositoryFactorySupport doCreateRepositoryFactory() { - JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext, - converter, dialect, publisher, operations); + JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(publisher, aggregateOperations, operations); jdbcRepositoryFactory.setQueryMappingConfiguration(queryMappingConfiguration); jdbcRepositoryFactory.setEntityCallbacks(entityCallbacks); jdbcRepositoryFactory.setBeanFactory(beanFactory); @@ -138,6 +141,10 @@ public void setJdbcOperations(NamedParameterJdbcOperations operations) { this.operations = operations; } + public void setJdbcAggregateOperations(JdbcAggregateOperations jdbcAggregateOperations) { + this.aggregateOperations = jdbcAggregateOperations; + } + public void setConverter(JdbcConverter converter) { Assert.notNull(converter, "JdbcConverter must not be null"); @@ -156,9 +163,6 @@ public void setBeanFactory(BeanFactory beanFactory) { @Override public void afterPropertiesSet() { - Assert.state(this.mappingContext != null, "MappingContext is required and must not be null"); - Assert.state(this.converter != null, "RelationalConverter is required and must not be null"); - if (this.operations == null) { Assert.state(beanFactory != null, "If no JdbcOperations are set a BeanFactory must be available"); @@ -166,25 +170,33 @@ public void afterPropertiesSet() { this.operations = beanFactory.getBean(NamedParameterJdbcOperations.class); } - if (this.dataAccessStrategy == null) { + if (aggregateOperations == null) { + + Assert.state(this.mappingContext != null, "MappingContext is required and must not be null"); + Assert.state(this.converter != null, "RelationalConverter is required and must not be null"); + + if (this.dataAccessStrategy == null) { + + Assert.state(beanFactory != null, "If no DataAccessStrategy is set a BeanFactory must be available"); - Assert.state(beanFactory != null, "If no DataAccessStrategy is set a BeanFactory must be available"); + this.dataAccessStrategy = this.beanFactory.getBeanProvider(DataAccessStrategy.class) // + .getIfAvailable(() -> { - this.dataAccessStrategy = this.beanFactory.getBeanProvider(DataAccessStrategy.class) // - .getIfAvailable(() -> { + Assert.state(this.dialect != null, "Dialect is required and must not be null"); - Assert.state(this.dialect != null, "Dialect is required and must not be null"); + SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(this.mappingContext, this.converter, + this.dialect); + SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(this.mappingContext, this.converter); + InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(this.operations, this.dialect); - SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(this.mappingContext, this.converter, - this.dialect); - SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(this.mappingContext, this.converter); - InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(this.operations, this.dialect); + DataAccessStrategyFactory factory = new DataAccessStrategyFactory(sqlGeneratorSource, this.converter, + this.operations, sqlParametersFactory, insertStrategyFactory); - DataAccessStrategyFactory factory = new DataAccessStrategyFactory(sqlGeneratorSource, this.converter, - this.operations, sqlParametersFactory, insertStrategyFactory); + return factory.create(); + }); + } - return factory.create(); - }); + aggregateOperations = new JdbcAggregateTemplate(publisher, converter, dataAccessStrategy); } if (this.queryMappingConfiguration == null) { diff --git a/spring-data-jdbc/src/main/resources/META-INF/spring.factories b/spring-data-jdbc/src/main/resources/META-INF/spring.factories index cc0d5cce5e..290e0c60d0 100644 --- a/spring-data-jdbc/src/main/resources/META-INF/spring.factories +++ b/spring-data-jdbc/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory -org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=org.springframework.data.jdbc.repository.config.DialectResolver.DefaultDialectProvider +org.springframework.data.jdbc.dialect.DialectResolver$JdbcDialectProvider=org.springframework.data.jdbc.dialect.DialectResolver.DefaultDialectProvider diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java index 7ccf063687..0319185e8a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java @@ -22,22 +22,13 @@ import static org.springframework.data.jdbc.testing.TestDatabaseFeatures.Feature.*; import java.time.LocalDateTime; +import java.util.*; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; import java.util.function.Function; import java.util.stream.IntStream; import org.junit.jupiter.api.Test; 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; @@ -51,8 +42,6 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Persistable; 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.EnabledOnFeature; import org.springframework.data.jdbc.testing.IntegrationTest; import org.springframework.data.jdbc.testing.TestClass; @@ -917,9 +906,8 @@ void readOnlyGetsLoadedButNotWritten() { template.save(entity); - assertThat( - jdbcTemplate.queryForObject("SELECT read_only FROM with_read_only", Collections.emptyMap(), String.class)) - .isEqualTo("from-db"); + assertThat(jdbcTemplate.queryForObject("SELECT read_only FROM with_read_only", Collections.emptyMap(), + String.class)).isEqualTo("from-db"); } @Test @@ -1258,7 +1246,8 @@ void recordOfSet() { @Test // GH-1656 void mapWithEnumKey() { - EnumMapOwner enumMapOwner = template.save(new EnumMapOwner(null, "OwnerName", Map.of(Color.BLUE, new MapElement("Element")))); + EnumMapOwner enumMapOwner = template.save( + new EnumMapOwner(null, "OwnerName", Map.of(Color.BLUE, new MapElement("Element")))); Iterable enumMapOwners = template.findAll(EnumMapOwner.class); @@ -2086,7 +2075,6 @@ record Book(String name) { record EnumMapOwner(@Id Long id, String name, Map map) { } - @Configuration @Import(TestConfiguration.class) static class Config { @@ -2095,12 +2083,6 @@ static class Config { TestClass testClass() { return TestClass.of(JdbcAggregateTemplateIntegrationTests.class); } - - @Bean - JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context, - DataAccessStrategy dataAccessStrategy, JdbcConverter converter) { - return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy); - } } @ContextConfiguration(classes = Config.class) 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 3f8f6ce935..5560ea19f8 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 @@ -23,18 +23,14 @@ import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.Test; 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.DatabaseType; import org.springframework.data.jdbc.testing.EnabledOnDatabase; import org.springframework.data.jdbc.testing.IntegrationTest; import org.springframework.data.jdbc.testing.TestConfiguration; -import org.springframework.data.relational.core.mapping.RelationalMappingContext; /** * Integration tests for {@link JdbcAggregateTemplate} and it's handling of immutable entities. @@ -602,11 +598,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/JdbcAggregateTemplateSchemaIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java index 8bd2d96a99..b62eb70b6a 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 @@ -16,22 +16,16 @@ package org.springframework.data.jdbc.core; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.jdbc.testing.TestDatabaseFeatures.Feature.*; import org.junit.jupiter.api.Test; 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.EnabledOnFeature; import org.springframework.data.jdbc.testing.IntegrationTest; 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; /** @@ -86,12 +80,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 d9e6ed3368..e155cb00b7 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 @@ -74,7 +74,7 @@ public void setUp() { RelationalMappingContext mappingContext = new RelationalMappingContext(); JdbcConverter converter = new MappingJdbcConverter(mappingContext, relationResolver); - template = new JdbcAggregateTemplate(eventPublisher, mappingContext, converter, dataAccessStrategy); + template = new JdbcAggregateTemplate(eventPublisher, converter, dataAccessStrategy); 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 1e3b30f4ca..327f33d1a1 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 @@ -27,12 +27,14 @@ import org.junit.jupiter.api.Test; 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.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.Import; 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.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory; @@ -40,6 +42,7 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.SqlGeneratorSource; import org.springframework.data.jdbc.core.convert.SqlParametersFactory; +import org.springframework.data.jdbc.dialect.DialectResolver; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean; import org.springframework.data.jdbc.testing.IntegrationTest; @@ -71,6 +74,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, + "aggregateOperations"); public static final RowMapper DUMMY_ENTITY_ROW_MAPPER = mock(RowMapper.class); public static final RowMapper STRING_ROW_MAPPER = mock(RowMapper.class); @@ -81,9 +86,15 @@ public class EnableJdbcRepositoriesIntegrationTests { @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() { @@ -91,6 +102,7 @@ public static void setup() { MAPPER_MAP.setAccessible(true); OPERATIONS.setAccessible(true); DATA_ACCESS_STRATEGY.setAccessible(true); + AGGREGATE_OPERATIONS.setAccessible(true); } @Test // DATAJDBC-100 @@ -125,6 +137,19 @@ public void jdbcOperationsRef() { assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy); } + @Test + public void jdbcAggregateOperationsRef() { + + JdbcAggregateOperations aggregateOperations = (JdbcAggregateOperations) ReflectionUtils.getField( + AGGREGATE_OPERATIONS, factoryBean); + assertThat(aggregateOperations).isNotSameAs(defaultJdbcAggregateOperations) + .isSameAs(qualifierJdbcAggregateOperations); + + DataAccessStrategy dataAccessStrategy = (DataAccessStrategy) ReflectionUtils.getField(DATA_ACCESS_STRATEGY, + factoryBean); + assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy); + } + interface DummyRepository extends CrudRepository { } @@ -145,6 +170,7 @@ public void setId(Long id) { @EnableJdbcRepositories(considerNestedRepositories = true, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DummyRepository.class), jdbcOperationsRef = "qualifierJdbcOperations", dataAccessStrategyRef = "qualifierDataAccessStrategy", + jdbcAggregateOperationsRef = "qualifierJdbcAggregateOperations", repositoryBaseClass = DummyRepositoryBaseClass.class) @Import(TestConfiguration.class) static class Config { @@ -167,14 +193,19 @@ DataAccessStrategy defaultDataAccessStrategy( @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, RelationalMappingContext context, JdbcConverter converter, Dialect dialect) { return new DataAccessStrategyFactory(new SqlGeneratorSource(context, converter, dialect), converter, template, - new SqlParametersFactory(context, converter), - new InsertStrategyFactory(template, dialect)).create(); + new SqlParametersFactory(context, converter), new InsertStrategyFactory(template, dialect)).create(); } @Bean Dialect jdbcDialect(@Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations operations) { return DialectResolver.getDialect(operations.getJdbcOperations()); } + + @Bean("qualifierJdbcAggregateOperations") + JdbcAggregateOperations jdbcAggregateOperations(ApplicationContext publisher, JdbcConverter converter, + @Qualifier("qualifierDataAccessStrategy") DataAccessStrategy dataAccessStrategy) { + return new JdbcAggregateTemplate(publisher, converter, dataAccessStrategy); + } } private static class DummyRepositoryBaseClass implements CrudRepository { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java index 99fbade759..839d4ad313 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java @@ -40,8 +40,11 @@ import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.H2Dialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.CrudRepository; +import org.springframework.jdbc.core.ConnectionCallback; +import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.test.util.ReflectionTestUtils; @@ -66,6 +69,11 @@ public class JdbcRepositoryFactoryBeanUnitTests { @Mock(answer = Answers.RETURNS_DEEP_STUBS) ListableBeanFactory beanFactory; @Mock Dialect dialect; + @Mock + JdbcOperations operations; + @Mock + NamedParameterJdbcOperations namedParameterJdbcOperations; + RelationalMappingContext mappingContext; @BeforeEach @@ -76,7 +84,9 @@ public void setUp() { // Setup standard configuration factoryBean = new JdbcRepositoryFactoryBean<>(DummyEntityRepository.class); - when(beanFactory.getBean(NamedParameterJdbcOperations.class)).thenReturn(mock(NamedParameterJdbcOperations.class)); + when(operations.execute(any(ConnectionCallback.class))).thenReturn(H2Dialect.INSTANCE); + when(namedParameterJdbcOperations.getJdbcOperations()).thenReturn(operations); + when(beanFactory.getBean(NamedParameterJdbcOperations.class)).thenReturn(namedParameterJdbcOperations); ObjectProvider provider = mock(ObjectProvider.class); when(beanFactory.getBeanProvider(DataAccessStrategy.class)).thenReturn(provider); 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 b84d93fe6b..c7721b00b9 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 @@ -26,6 +26,7 @@ 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; @@ -34,11 +35,13 @@ import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; 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.*; import org.springframework.data.jdbc.core.dialect.JdbcDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; -import org.springframework.data.jdbc.repository.config.DialectResolver; +import org.springframework.data.jdbc.dialect.DialectResolver; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.core.dialect.Dialect; @@ -169,6 +172,12 @@ Dialect jdbcDialect(NamedParameterJdbcOperations operations) { return DialectResolver.getDialect(operations.getJdbcOperations()); } + @Bean + JdbcAggregateOperations jdbcAggregateOperations(ApplicationContext publisher, JdbcConverter converter, + @Qualifier("defaultDataAccessStrategy") DataAccessStrategy dataAccessStrategy) { + return new JdbcAggregateTemplate(publisher, converter, dataAccessStrategy); + } + @Lazy @Bean TestDatabaseFeatures features(NamedParameterJdbcOperations operations) { From aa2040dc7aa4271db5c2e5a4fceaad4792a17f07 Mon Sep 17 00:00:00 2001 From: Tomohiko Ozawa Date: Mon, 25 Dec 2023 10:33:21 +0900 Subject: [PATCH 2/3] add comment for test case --- .../config/EnableJdbcRepositoriesIntegrationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 327f33d1a1..81d4f5d059 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 @@ -137,7 +137,7 @@ public void jdbcOperationsRef() { assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy); } - @Test + @Test // GH-1704 public void jdbcAggregateOperationsRef() { JdbcAggregateOperations aggregateOperations = (JdbcAggregateOperations) ReflectionUtils.getField( From fca5f7a6f9fe1d936f2b2d552de0df5f68e317a2 Mon Sep 17 00:00:00 2001 From: Tomohiko Ozawa Date: Tue, 6 Feb 2024 19:12:36 +0900 Subject: [PATCH 3/3] keep public API unchanged --- .../data/jdbc/core/JdbcAggregateTemplate.java | 63 ++++++++++++++++++- .../config/AbstractJdbcConfiguration.java | 29 +++++---- 2 files changed, 80 insertions(+), 12 deletions(-) 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 807fef93fc..75dea3166d 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 @@ -88,7 +88,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { * * @param publisher must not be {@literal null}. * @param dataAccessStrategy must not be {@literal null}. - * @since 1.1 + * @since 3.3 */ public JdbcAggregateTemplate(ApplicationContext publisher, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { @@ -115,6 +115,7 @@ public JdbcAggregateTemplate(ApplicationContext publisher, JdbcConverter convert * * @param publisher must not be {@literal null}. * @param dataAccessStrategy must not be {@literal null}. + * @since 3.3 */ public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { @@ -132,6 +133,66 @@ public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcConverter this.executor = new AggregateChangeExecutor(converter, accessStrategy); } + /** + * Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationContext}, {@link RelationalMappingContext} and + * {@link DataAccessStrategy}. + * + * @param publisher must not be {@literal null}. + * @param context must not be {@literal null}. + * @param dataAccessStrategy must not be {@literal null}. + * @since 1.1 + * @deprecated since 3.3, use {@link JdbcAggregateTemplate(ApplicationContext, JdbcConverter, DataAccessStrategy)} + * instead. + */ + @Deprecated(since = "3.3") + public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingContext context, JdbcConverter converter, + DataAccessStrategy dataAccessStrategy) { + + Assert.notNull(publisher, "ApplicationContext must not be null"); + Assert.notNull(context, "RelationalMappingContext must not be null"); + Assert.notNull(converter, "RelationalConverter must not be null"); + Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null"); + + this.eventDelegate.setPublisher(publisher); + this.context = context; + this.accessStrategy = dataAccessStrategy; + this.converter = converter; + + this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context); + + this.executor = new AggregateChangeExecutor(converter, accessStrategy); + + setEntityCallbacks(EntityCallbacks.create(publisher)); + } + + /** + * Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationEventPublisher}, + * {@link RelationalMappingContext} and {@link DataAccessStrategy}. + * + * @param publisher must not be {@literal null}. + * @param context must not be {@literal null}. + * @param dataAccessStrategy must not be {@literal null}. + * @deprecated since 3.3, use {@link JdbcAggregateTemplate(ApplicationEventPublisher, JdbcConverter, + * DataAccessStrategy)} instead. + */ + @Deprecated(since = "3.3") + public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMappingContext context, + JdbcConverter converter, DataAccessStrategy dataAccessStrategy) { + + Assert.notNull(publisher, "ApplicationEventPublisher must not be null"); + Assert.notNull(context, "RelationalMappingContext must not be null"); + Assert.notNull(converter, "RelationalConverter must not be null"); + Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null"); + + this.eventDelegate.setPublisher(publisher); + this.context = context; + this.accessStrategy = dataAccessStrategy; + this.converter = converter; + + this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context); + this.executor = new AggregateChangeExecutor(converter, accessStrategy); + } + /** * Sets the callbacks to be invoked on life cycle events. * 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 2d87f8ab68..b3501ab0e3 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 @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; @@ -104,7 +105,7 @@ public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException { * * @param namingStrategy optional {@link NamingStrategy}. Use * {@link org.springframework.data.relational.core.mapping.DefaultNamingStrategy#INSTANCE} as fallback. - * @param customConversions see {@link #jdbcCustomConversions(Optional)}. + * @param customConversions see {@link #jdbcCustomConversions()}. * @param jdbcManagedTypes JDBC managed types, typically discovered through {@link #jdbcManagedTypes() an entity * scan}. * @return must not be {@literal null}. @@ -125,7 +126,7 @@ public JdbcMappingContext jdbcMappingContext(Optional namingStra * {@link #jdbcMappingContext(Optional, JdbcCustomConversions, RelationalManagedTypes)}. * * @see #jdbcMappingContext(Optional, JdbcCustomConversions, RelationalManagedTypes) - * @see #jdbcCustomConversions(Optional) + * @see #jdbcCustomConversions() * @return must not be {@literal null}. */ @Bean @@ -148,17 +149,23 @@ public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParam * @return will never be {@literal null}. */ @Bean - public JdbcCustomConversions jdbcCustomConversions(Optional dialect) { - return dialect.map(d -> { - SimpleTypeHolder simpleTypeHolder = d.simpleTypes().isEmpty() - ? JdbcSimpleTypes.HOLDER - : new SimpleTypeHolder(d.simpleTypes(), JdbcSimpleTypes.HOLDER); - return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(d)), - userConverters()); - }).orElseGet(() -> { + public JdbcCustomConversions jdbcCustomConversions() { + + try { + + Dialect dialect = applicationContext.getBean(Dialect.class); + SimpleTypeHolder simpleTypeHolder = dialect.simpleTypes().isEmpty() ? JdbcSimpleTypes.HOLDER + : new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); + + return new JdbcCustomConversions( + CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), userConverters()); + + } catch (NoSuchBeanDefinitionException exception) { + LOG.warn("No dialect found; CustomConversions will be configured without dialect specific conversions"); + return new JdbcCustomConversions(); - }); + } } protected List userConverters() {