From 9e6484310d65ec07030c441575ebe7ce39bf13f4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 28 Oct 2025 10:31:48 +0100 Subject: [PATCH 1/2] Prepare issue branch. --- pom.xml | 2 +- spring-data-jdbc-distribution/pom.xml | 2 +- spring-data-jdbc/pom.xml | 4 ++-- spring-data-r2dbc/pom.xml | 4 ++-- spring-data-relational/pom.xml | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 01115a9d8c..de46cbfee9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT pom Spring Data Relational Parent diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml index b3c39e64c3..4f638359f0 100644 --- a/spring-data-jdbc-distribution/pom.xml +++ b/spring-data-jdbc-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT ../pom.xml diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml index 052c9fed78..5273ab22f4 100644 --- a/spring-data-jdbc/pom.xml +++ b/spring-data-jdbc/pom.xml @@ -6,7 +6,7 @@ 4.0.0 spring-data-jdbc - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT Spring Data JDBC Spring Data module for JDBC repositories. @@ -15,7 +15,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT diff --git a/spring-data-r2dbc/pom.xml b/spring-data-r2dbc/pom.xml index 46341f7275..df62a88bc7 100644 --- a/spring-data-r2dbc/pom.xml +++ b/spring-data-r2dbc/pom.xml @@ -6,7 +6,7 @@ 4.0.0 spring-data-r2dbc - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT Spring Data R2DBC Spring Data module for R2DBC @@ -15,7 +15,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml index 6fc709727e..e6a5a38159 100644 --- a/spring-data-relational/pom.xml +++ b/spring-data-relational/pom.xml @@ -6,7 +6,7 @@ 4.0.0 spring-data-relational - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT Spring Data Relational Spring Data Relational support @@ -14,7 +14,7 @@ org.springframework.data spring-data-relational-parent - 4.0.0-SNAPSHOT + 5.0.0-GH-2165-SNAPSHOT From 80a885fea4c43dc9fdcaa42b2ea9bd94c1d9adaa Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 28 Oct 2025 10:32:00 +0100 Subject: [PATCH 2/2] Introduce `JdbcConfiguration` and extract factory methods used from `AbstractJdbcConfiguration`. --- .../config/AbstractJdbcConfiguration.java | 83 ++------- .../repository/config/JdbcConfiguration.java | 169 ++++++++++++++++++ .../config/MyBatisJdbcConfiguration.java | 5 +- ...ractJdbcConfigurationIntegrationTests.java | 7 +- ...atisJdbcConfigurationIntegrationTests.java | 6 +- .../ROOT/pages/jdbc/getting-started.adoc | 12 +- .../modules/ROOT/pages/jdbc/mapping.adoc | 4 +- .../ROOT/pages/r2dbc/getting-started.adoc | 8 +- .../modules/ROOT/pages/r2dbc/mapping.adoc | 2 +- 9 files changed, 204 insertions(+), 92 deletions(-) create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java 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 bdc1f3c1fb..fa9b00e95e 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 @@ -15,7 +15,6 @@ */ package org.springframework.data.jdbc.repository.config; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -23,8 +22,6 @@ import java.util.Optional; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -32,34 +29,23 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.converter.Converter; -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.DataAccessStrategy; -import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory; -import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory; import org.springframework.data.jdbc.core.convert.IdGeneratingEntityCallback; import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; -import org.springframework.data.jdbc.core.convert.MappingJdbcConverter; import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration; import org.springframework.data.jdbc.core.convert.RelationResolver; import org.springframework.data.jdbc.core.dialect.DialectResolver; -import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns; 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.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.RelationalManagedTypes; import org.springframework.data.relational.core.conversion.RelationalConverter; import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.mapping.DefaultNamingStrategy; import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.Table; -import org.springframework.data.util.TypeScanner; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; -import org.springframework.util.StringUtils; /** * Beans that must be registered for Spring Data JDBC to work. @@ -77,8 +63,6 @@ @Configuration(proxyBeanMethods = false) public class AbstractJdbcConfiguration implements ApplicationContextAware { - private static final Log LOG = LogFactory.getLog(AbstractJdbcConfiguration.class); - @SuppressWarnings("NullAway.Init") private ApplicationContext applicationContext; private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY; @@ -96,7 +80,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware { protected Collection getMappingBasePackages() { Package mappingBasePackage = getClass().getPackage(); - return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName()); + return mappingBasePackage == null ? List.of() : List.of(mappingBasePackage.getName()); } /** @@ -124,13 +108,7 @@ public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException { @Bean public JdbcMappingContext jdbcMappingContext(Optional namingStrategy, JdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) { - - JdbcMappingContext mappingContext = JdbcMappingContext - .forQuotedIdentifiers(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE)); - mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); - mappingContext.setManagedTypes(jdbcManagedTypes); - - return mappingContext; + return JdbcConfiguration.createMappingContext(jdbcManagedTypes, customConversions, namingStrategy.orElse(null)); } /** @@ -143,7 +121,7 @@ public JdbcMappingContext jdbcMappingContext(Optional namingStra */ @Bean public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext, - NamedParameterJdbcOperations operations, Dialect dialect) { + NamedParameterJdbcOperations operations, JdbcDialect dialect) { return new IdGeneratingEntityCallback(mappingContext, dialect, operations); } @@ -157,25 +135,14 @@ public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingCont */ @Bean public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations, - @Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, Dialect dialect) { - - JdbcArrayColumns arrayColumns = JdbcDialect.getArraySupport(dialect); - DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns); - - MappingJdbcConverter mappingJdbcConverter = new MappingJdbcConverter(mappingContext, relationResolver, conversions, - jdbcTypeFactory); - - if (operations.getJdbcOperations() instanceof JdbcTemplate jdbcTemplate) { - mappingJdbcConverter.setExceptionTranslator(jdbcTemplate.getExceptionTranslator()); - } - - return mappingJdbcConverter; + @Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, JdbcDialect dialect) { + return JdbcConfiguration.createConverter(mappingContext, operations, relationResolver, conversions, dialect); } /** * Register custom {@link Converter}s in a {@link JdbcCustomConversions} object if required. These * {@link JdbcCustomConversions} will be registered with the - * {@link #jdbcConverter(JdbcMappingContext, NamedParameterJdbcOperations, RelationResolver, JdbcCustomConversions, Dialect)}. + * {@link #jdbcConverter(JdbcMappingContext, NamedParameterJdbcOperations, RelationResolver, JdbcCustomConversions, JdbcDialect)}. * Returns an empty {@link JdbcCustomConversions} instance by default. * * @return will never be {@literal null}. @@ -183,31 +150,14 @@ public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParam @Bean public JdbcCustomConversions jdbcCustomConversions() { - Dialect dialect = applicationContext.getBeanProvider(Dialect.class).getIfAvailable(); - - if (dialect == null) { - LOG.warn("No JdbcDialect bean found; CustomConversions will be configured without dialect-specific types."); - return new JdbcCustomConversions(); - } - - SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); - - return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), - userConverters()); + JdbcDialect dialect = applicationContext.getBean(JdbcDialect.class); + return JdbcConfiguration.createCustomConversions(dialect, userConverters()); } protected List userConverters() { return Collections.emptyList(); } - private List storeConverters(Dialect dialect) { - - List converters = new ArrayList<>(); - converters.addAll(dialect.getConverters()); - converters.addAll(JdbcCustomConversions.storeConverters()); - return converters; - } - /** * Register a {@link JdbcAggregateTemplate} as a bean for easy use in applications that need a lower level of * abstraction than the normal repository abstraction. @@ -232,8 +182,8 @@ public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicatio */ @Bean public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter, - JdbcMappingContext context, Dialect dialect) { - return new DataAccessStrategyFactory(jdbcConverter, operations, dialect, this.queryMappingConfiguration).create(); + JdbcMappingContext context, JdbcDialect dialect) { + return JdbcConfiguration.createDataAccessStrategy(operations, jdbcConverter, queryMappingConfiguration, dialect); } /** @@ -245,7 +195,7 @@ public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations op * @throws DialectResolver.NoDialectException if the {@link Dialect} cannot be determined. */ @Bean - public Dialect jdbcDialect(NamedParameterJdbcOperations operations) { + public JdbcDialect jdbcDialect(NamedParameterJdbcOperations operations) { return DialectResolver.getDialect(operations.getJdbcOperations()); } @@ -286,16 +236,7 @@ protected Set> getInitialEntitySet() throws ClassNotFoundException { * @return a set of classes identified as entities. * @since 3.0 */ - @SuppressWarnings("unchecked") protected Set> scanForEntities(String basePackage) { - - if (!StringUtils.hasText(basePackage)) { - return Collections.emptySet(); - } - - return TypeScanner.typeScanner(AbstractJdbcConfiguration.class.getClassLoader()) // - .forTypesAnnotatedWith(Table.class) // - .scanPackages(basePackage) // - .collectAsSet(); + return JdbcConfiguration.scanForEntities(basePackage); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java new file mode 100644 index 0000000000..90f84186a0 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java @@ -0,0 +1,169 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jdbc.repository.config; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.jspecify.annotations.Nullable; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.CustomConversions; +import org.springframework.data.jdbc.core.JdbcAggregateOperations; +import org.springframework.data.jdbc.core.convert.DataAccessStrategy; +import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory; +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.MappingJdbcConverter; +import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration; +import org.springframework.data.jdbc.core.convert.RelationResolver; +import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns; +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.mapping.model.SimpleTypeHolder; +import org.springframework.data.relational.RelationalManagedTypes; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.mapping.DefaultNamingStrategy; +import org.springframework.data.relational.core.mapping.NamingStrategy; +import org.springframework.data.relational.core.mapping.Table; +import org.springframework.data.util.TypeScanner; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.util.StringUtils; + +/** + * Utility class to providing factory methods for JDBC infrastructure components. + *

+ * Mainly for use within the framework or for configuration arrangements that require customization of configuration. + * + * @author Mark Paluch + * @since 4.0 + */ +public final class JdbcConfiguration { + + private JdbcConfiguration() {} + + /** + * Register a {@link JdbcMappingContext} and apply an optional {@link NamingStrategy}. + * + * @param jdbcManagedTypes JDBC managed types. + * @param customConversions the custom conversions. + * @param namingStrategy optional {@link NamingStrategy}. Use {@link DefaultNamingStrategy#INSTANCE} as fallback. + * @return must not be {@literal null}. + */ + public static JdbcMappingContext createMappingContext(RelationalManagedTypes jdbcManagedTypes, + JdbcCustomConversions customConversions, @Nullable NamingStrategy namingStrategy) { + + JdbcMappingContext mappingContext = JdbcMappingContext + .forQuotedIdentifiers(namingStrategy != null ? namingStrategy : DefaultNamingStrategy.INSTANCE); + mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); + mappingContext.setManagedTypes(jdbcManagedTypes); + + return mappingContext; + } + + /** + * Creates a {@link JdbcConverter}. + * + * @param mappingContext must not be {@literal null}. + * @param operations must not be {@literal null}. + * @param relationResolver must not be {@literal null}. + * @param conversions must not be {@literal null}. + * @param dialect the JDBC dialect in use. + * @return must not be {@literal null}. + */ + public static JdbcConverter createConverter(JdbcMappingContext mappingContext, + NamedParameterJdbcOperations operations, RelationResolver relationResolver, JdbcCustomConversions conversions, + JdbcDialect dialect) { + + JdbcArrayColumns arrayColumns = JdbcDialect.getArraySupport(dialect); + DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns); + + MappingJdbcConverter mappingJdbcConverter = new MappingJdbcConverter(mappingContext, relationResolver, conversions, + jdbcTypeFactory); + + if (operations.getJdbcOperations() instanceof JdbcTemplate jdbcTemplate) { + mappingJdbcConverter.setExceptionTranslator(jdbcTemplate.getExceptionTranslator()); + } + + return mappingJdbcConverter; + } + + /** + * Register custom {@link Converter}s in a {@link JdbcCustomConversions} object if required. + * + * @param dialect the JDBC dialect in use. + * @param userConverters list of user converters, must not be {@literal null}. + * @return will never be {@literal null}. + */ + public static JdbcCustomConversions createCustomConversions(JdbcDialect dialect, List userConverters) { + + SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); + + return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), + userConverters); + } + + private static List storeConverters(Dialect dialect) { + + List converters = new ArrayList<>(); + converters.addAll(dialect.getConverters()); + converters.addAll(JdbcCustomConversions.storeConverters()); + return converters; + } + + /** + * Create a {@link DataAccessStrategy} for reuse in the {@link JdbcAggregateOperations} and the {@link JdbcConverter}. + * Override this method to register a bean of type {@link DataAccessStrategy} if your use case requires a more + * specialized {@link DataAccessStrategy}. + * + * @param operations must not be {@literal null}. + * @param jdbcConverter must not be {@literal null}. + * @param mappingConfiguration mapping configuration, can be {@literal null}. + * @param dialect the JDBC dialect in use. + * @return will never be {@literal null}. + */ + public static DataAccessStrategy createDataAccessStrategy(NamedParameterJdbcOperations operations, + JdbcConverter jdbcConverter, @Nullable QueryMappingConfiguration mappingConfiguration, JdbcDialect dialect) { + return new DataAccessStrategyFactory(jdbcConverter, operations, dialect, + mappingConfiguration == null ? QueryMappingConfiguration.EMPTY : mappingConfiguration).create(); + } + + /** + * Scans the given base package for entities, i.e. JDBC-specific types annotated with {@link Table}. + * + * @param basePackage must not be {@literal null}. + * @return a set of classes identified as entities. + * @since 3.0 + */ + @SuppressWarnings("unchecked") + public static Set> scanForEntities(String basePackage) { + + if (!StringUtils.hasText(basePackage)) { + return Collections.emptySet(); + } + + return TypeScanner.typeScanner(JdbcConfiguration.class.getClassLoader()) // + .forTypesAnnotatedWith(Table.class) // + .scanPackages(basePackage) // + .collectAsSet(); + } + +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java index 6198fab51e..66b9f83cea 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java @@ -18,15 +18,16 @@ import java.util.Optional; import org.apache.ibatis.session.SqlSession; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration; +import org.springframework.data.jdbc.core.dialect.JdbcDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy; -import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; /** @@ -46,7 +47,7 @@ public class MyBatisJdbcConfiguration extends AbstractJdbcConfiguration { @Bean @Override public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter, - JdbcMappingContext context, Dialect dialect) { + JdbcMappingContext context, JdbcDialect dialect) { return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, jdbcConverter, operations, session, dialect, queryMappingConfiguration.orElse(QueryMappingConfiguration.EMPTY)); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java index 9c8ee97388..a83005eefe 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java @@ -25,6 +25,7 @@ import java.util.function.Consumer; import org.junit.jupiter.api.Test; + import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -36,9 +37,9 @@ import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; +import org.springframework.data.jdbc.core.dialect.JdbcDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.RelationalManagedTypes; -import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.dialect.LimitClause; import org.springframework.data.relational.core.dialect.LockClause; import org.springframework.data.relational.core.sql.render.SelectRenderContext; @@ -142,7 +143,7 @@ static class AbstractJdbcConfigurationUnderTest extends AbstractJdbcConfiguratio @Override @Bean - public Dialect jdbcDialect(NamedParameterJdbcOperations operations) { + public JdbcDialect jdbcDialect(NamedParameterJdbcOperations operations) { return new DummyDialect(); } @@ -165,7 +166,7 @@ private static class Blah {} private static class Blubb {} - private static class DummyDialect implements Dialect { + private static class DummyDialect implements JdbcDialect { @Override public LimitClause limit() { return null; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfigurationIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfigurationIntegrationTests.java index b0ad7a4b1a..d05023ae17 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfigurationIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfigurationIntegrationTests.java @@ -22,14 +22,14 @@ import org.apache.ibatis.session.SqlSession; import org.junit.jupiter.api.Test; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jdbc.core.convert.CascadingDataAccessStrategy; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; +import org.springframework.data.jdbc.core.dialect.JdbcDialect; import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy; -import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.test.util.ReflectionTestUtils; @@ -70,7 +70,7 @@ public static class MyBatisJdbcConfigurationUnderTest extends MyBatisJdbcConfigu @Override @Bean - public Dialect jdbcDialect(NamedParameterJdbcOperations operations) { + public JdbcDialect jdbcDialect(NamedParameterJdbcOperations operations) { return JdbcHsqlDbDialect.INSTANCE; } } diff --git a/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc b/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc index 168712e5af..01bbcdc6a9 100644 --- a/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc +++ b/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc @@ -148,13 +148,13 @@ There are a couple of things one might want to customize in this setup. [[jdbc.dialects]] == Dialects -Spring Data JDBC uses implementations of the interface `Dialect` to encapsulate behavior that is specific to a database or its JDBC driver. -By default, the javadoc:org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration[] attempts to determine the dialect from the database configuration by obtaining a connection and registering the correct `Dialect`. +Spring Data JDBC uses implementations of the interface `JdbcDialect` to encapsulate behavior that is specific to a database or its JDBC driver. +By default, the javadoc:org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration[] attempts to determine the dialect from the database configuration by obtaining a connection and registering the correct `JdbcDialect`. You override `AbstractJdbcConfiguration.jdbcDialect(NamedParameterJdbcOperations)` to customize dialect selection. If you use a database for which no dialect is available, then your application won’t start up. -In that case, you’ll have to ask your vendor to provide a `Dialect` implementation. -Alternatively, you can implement your own `Dialect`. +In that case, you’ll have to ask your vendor to provide a `JdbcDialect` implementation. +Alternatively, you can implement your own `JdbcDialect`. [TIP] ==== @@ -163,8 +163,8 @@ You can let Spring auto-discover your javadoc:org.springframework.data.jdbc.core `DialectResolver` discovers dialect provider implementations from the class path using Spring's `SpringFactoriesLoader`. To do so: -. Implement your own `Dialect`. -. Implement a `JdbcDialectProvider` returning the `Dialect`. +. Implement your own `JdbcDialect`. +. Implement a `JdbcDialectProvider` returning the `JdbcDialect`. . Register the provider by creating a `spring.factories` resource under `META-INF` and perform the registration by adding a line + `org.springframework.data.jdbc.core.dialect.DialectResolver$JdbcDialectProvider`=`. ==== diff --git a/src/main/antora/modules/ROOT/pages/jdbc/mapping.adoc b/src/main/antora/modules/ROOT/pages/jdbc/mapping.adoc index bc363b2ba6..61c2d203db 100644 --- a/src/main/antora/modules/ROOT/pages/jdbc/mapping.adoc +++ b/src/main/antora/modules/ROOT/pages/jdbc/mapping.adoc @@ -208,8 +208,8 @@ class MyJdbcConfiguration extends AbstractJdbcConfiguration { ---- NOTE: In previous versions of Spring Data JDBC it was recommended to directly overwrite `AbstractJdbcConfiguration.jdbcCustomConversions()`. -This is no longer necessary or even recommended, since that method assembles conversions intended for all databases, conversions registered by the `Dialect` used and conversions registered by the user. -If you are migrating from an older version of Spring Data JDBC and have `AbstractJdbcConfiguration.jdbcCustomConversions()` overwritten conversions from your `Dialect` will not get registered. +This is no longer necessary or even recommended, since that method assembles conversions intended for all databases, conversions registered by the `JdbcDialect` used and conversions registered by the user. +If you are migrating from an older version of Spring Data JDBC and have `AbstractJdbcConfiguration.jdbcCustomConversions()` overwritten conversions from your `JdbcDialect` will not get registered. [TIP] ==== diff --git a/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc b/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc index afb6df1d12..357d49b9f2 100644 --- a/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc +++ b/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc @@ -172,15 +172,15 @@ This approach lets you use the standard `io.r2dbc.spi.ConnectionFactory` instanc [[r2dbc.dialects]] == Dialects -Spring Data R2DBC uses a `Dialect` to encapsulate behavior that is specific to a database or its driver. +Spring Data R2DBC uses a `R2dbcDialect` to encapsulate behavior that is specific to a database or its driver. Spring Data R2DBC reacts to database specifics by inspecting the `ConnectionFactory` and selects the appropriate database dialect accordingly. If you use a database for which no dialect is available, then your application won’t start up. -In that case, you’ll have to ask your vendor to provide a `Dialect` implementation. -Alternatively, you can implement your own `Dialect`. +In that case, you’ll have to ask your vendor to provide a `R2dbcDialect` implementation. +Alternatively, you can implement your own `R2dbcDialect`. [TIP] ==== -Dialects are resolved by javadoc:org.springframework.data.r2dbc./dialect.DialectResolver[] from a `ConnectionFactory`, typically by inspecting `ConnectionFactoryMetadata`. +Dialects are resolved by javadoc:org.springframework.data.r2dbc.dialect.DialectResolver[] from a `ConnectionFactory`, typically by inspecting `ConnectionFactoryMetadata`. + You can let Spring auto-discover your `R2dbcDialect` by registering a class that implements `org.springframework.data.r2dbc.dialect.DialectResolver$R2dbcDialectProvider` through `META-INF/spring.factories`. `DialectResolver` discovers dialect provider implementations from the class path using Spring's `SpringFactoriesLoader`. To do so: diff --git a/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc b/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc index e25416b9ab..4fc7a4482b 100644 --- a/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc +++ b/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc @@ -53,7 +53,7 @@ You can do so by overriding `r2dbcMappingContext(Optional)` of ` Spring Data converts the letter casing of such a name to that form which is also used by the configured database when no quoting is used. Therefore, you can use unquoted names when creating tables, as long as you do not use keywords or special characters in your names. For databases that adhere to the SQL standard, this means that names are converted to upper case. -The quoting character and the way names get capitalized is controlled by the used `Dialect`. +The quoting character and the way names get capitalized is controlled by the used `R2dbcDialect`. See xref:r2dbc/getting-started.adoc#r2dbc.dialects[R2DBC Drivers] for how to configure custom dialects. .@Configuration class to configure R2DBC mapping support