From 413de0a8bddd560e3a74677ddd914f97d06facf0 Mon Sep 17 00:00:00 2001 From: mipo256 Date: Sun, 20 Apr 2025 16:05:52 +0300 Subject: [PATCH 1/2] GH-2031 Introduced new JDBC dialect counterparts Signed-off-by: mipo256 --- .../jdbc/core/convert/JdbcArrayColumns.java | 7 ---- .../jdbc/core/dialect/JdbcDb2Dialect.java | 2 +- .../data/jdbc/core/dialect/JdbcDialect.java | 6 ++- .../data/jdbc/core/dialect/JdbcH2Dialect.java | 37 ++++++++++++++++++ .../jdbc/core/dialect/JdbcHsqlDbDialect.java | 29 ++++++++++++++ .../jdbc/core/dialect/JdbcMariaDbDialect.java | 32 +++++++++++++++ .../jdbc/core/dialect/JdbcMySqlDialect.java | 5 ++- .../jdbc/core/dialect/JdbcOracleDialect.java | 39 +++++++++++++++++++ .../core/dialect/JdbcSqlServerDialect.java | 2 +- .../repository/config/DialectResolver.java | 20 +++++----- .../DefaultDataAccessStrategyUnitTests.java | 3 +- .../IdGeneratingEntityCallbackTest.java | 24 ++++++------ .../jdbc/core/convert/NonQuotingDialect.java | 5 ++- .../core/convert/SqlGeneratorUnitTests.java | 28 +++++++------ .../mybatis/MyBatisHsqlIntegrationTests.java | 10 ++--- .../DeclaredQueryRepositoryUnitTests.java | 11 ++++-- .../SimpleJdbcRepositoryEventsUnitTests.java | 31 ++++++++++----- ...atisJdbcConfigurationIntegrationTests.java | 3 +- .../query/PartTreeJdbcQueryUnitTests.java | 3 +- .../JdbcQueryLookupStrategyUnitTests.java | 5 ++- .../relational/core/dialect/Db2Dialect.java | 4 ++ .../relational/core/dialect/H2Dialect.java | 7 +++- .../core/dialect/HsqlDbDialect.java | 4 ++ .../relational/core/dialect/MySqlDialect.java | 4 ++ .../core/dialect/OracleDialect.java | 6 ++- .../core/dialect/PostgresDialect.java | 7 +++- .../core/dialect/SqlServerDialect.java | 4 ++ .../core/dialect/HsqlDbDialectUnitTests.java | 18 ++++----- .../MySqlDialectRenderingUnitTests.java | 2 +- .../core/dialect/MySqlDialectUnitTests.java | 12 +++--- 30 files changed, 282 insertions(+), 88 deletions(-) create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java index e3df13ddc7..3086765efc 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java @@ -88,12 +88,5 @@ enum DefaultSupport implements JdbcArrayColumns { public boolean isSupported() { return true; } - - @Override - public String getArrayTypeName(SQLType jdbcType) { - return jdbcType.getName(); - } - } - } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java index 86027b9ca7..a627fabe2b 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java @@ -33,7 +33,7 @@ * @author Christoph Strobl * @since 2.3 */ -public class JdbcDb2Dialect extends Db2Dialect { +public class JdbcDb2Dialect extends Db2Dialect implements JdbcDialect { public static JdbcDb2Dialect INSTANCE = new JdbcDb2Dialect(); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java index d20b935700..8308eb536e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java @@ -22,6 +22,7 @@ * {@link org.springframework.data.relational.core.dialect.ArrayColumns} that offer JDBC specific functionality. * * @author Jens Schauder + * @author Mikhail Polivakha * @since 2.3 */ public interface JdbcDialect extends Dialect { @@ -33,6 +34,7 @@ public interface JdbcDialect extends Dialect { * @return the JDBC specific array support object that describes how array-typed columns are supported by this * dialect. */ - @Override - JdbcArrayColumns getArraySupport(); + default JdbcArrayColumns getArraySupport() { + return JdbcArrayColumns.Unsupported.INSTANCE; + } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java new file mode 100644 index 0000000000..34adfff3f2 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java @@ -0,0 +1,37 @@ +/* + * 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.core.dialect; + +import org.springframework.data.jdbc.core.convert.JdbcArrayColumns; +import org.springframework.data.relational.core.dialect.H2Dialect; + +/** + * JDBC specific H2 Dialect. + * + * @author Mikhail Polivakha + */ +public class JdbcH2Dialect extends H2Dialect implements JdbcDialect { + + public static JdbcH2Dialect INSTANCE = new JdbcH2Dialect(); + + @Override + public JdbcArrayColumns getArraySupport() { + return new JdbcH2ArrayColumns(); + } + + public static class JdbcH2ArrayColumns extends H2ArrayColumns implements JdbcArrayColumns { } +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java new file mode 100644 index 0000000000..ef64bdce21 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java @@ -0,0 +1,29 @@ +/* + * 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.core.dialect; + +import org.springframework.data.relational.core.dialect.HsqlDbDialect; + +/** + * JDBC specific HsqlDB Dialect. + * + * @author Mikhail Polivakha + */ +public class JdbcHsqlDbDialect extends HsqlDbDialect implements JdbcDialect { + + public static JdbcHsqlDbDialect INSTANCE = new JdbcHsqlDbDialect(); +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java new file mode 100644 index 0000000000..676c11a8bc --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java @@ -0,0 +1,32 @@ +/* + * 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.core.dialect; + +import org.springframework.data.relational.core.dialect.MariaDbDialect; +import org.springframework.data.relational.core.sql.IdentifierProcessing; + +/** + * JDBC specific MariaDb Dialect. + * + * @author Mikhail Polivakha + */ +public class JdbcMariaDbDialect extends MariaDbDialect implements JdbcDialect { + + public JdbcMariaDbDialect(IdentifierProcessing identifierProcessing) { + super(identifierProcessing); + } +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java index 4295d60e0c..90529bef0a 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java @@ -38,9 +38,12 @@ * * @author Jens Schauder * @author Christoph Strobl + * @author Mikhail Polivakha * @since 2.3 */ -public class JdbcMySqlDialect extends MySqlDialect { +public class JdbcMySqlDialect extends MySqlDialect implements JdbcDialect { + + public static JdbcMySqlDialect INSTANCE = new JdbcMySqlDialect(); public JdbcMySqlDialect(IdentifierProcessing identifierProcessing) { super(identifierProcessing); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java new file mode 100644 index 0000000000..86dd5ee147 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java @@ -0,0 +1,39 @@ +/* + * 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.core.dialect; + +import org.springframework.data.jdbc.core.convert.JdbcArrayColumns; +import org.springframework.data.relational.core.dialect.ArrayColumns; +import org.springframework.data.relational.core.dialect.ObjectArrayColumns; +import org.springframework.data.relational.core.dialect.OracleDialect; + +/** + * JDBC specific Oracle Dialect. + * + * @author Mikhail Polivakha + */ +public class JdbcOracleDialect extends OracleDialect implements JdbcDialect { + + public static JdbcOracleDialect INSTANCE = new JdbcOracleDialect(); + + @Override + public JdbcArrayColumns getArraySupport() { + return new JdbcOracleArrayColumns(); + } + + public static class JdbcOracleArrayColumns extends ObjectArrayColumns implements JdbcArrayColumns { } +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java index e147e841d2..d3d431ec4e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java @@ -35,7 +35,7 @@ * @author Mikhail Polivakha * @since 2.3 */ -public class JdbcSqlServerDialect extends SqlServerDialect { +public class JdbcSqlServerDialect extends SqlServerDialect implements JdbcDialect { public static JdbcSqlServerDialect INSTANCE = new JdbcSqlServerDialect(); 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/repository/config/DialectResolver.java index 99eb15cf61..21a4c44021 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/repository/config/DialectResolver.java @@ -29,14 +29,15 @@ import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.dao.NonTransientDataAccessException; import org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect; +import org.springframework.data.jdbc.core.dialect.JdbcDialect; +import org.springframework.data.jdbc.core.dialect.JdbcH2Dialect; +import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; +import org.springframework.data.jdbc.core.dialect.JdbcMariaDbDialect; import org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect; +import org.springframework.data.jdbc.core.dialect.JdbcOracleDialect; import org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect; import org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect; import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.dialect.H2Dialect; -import org.springframework.data.relational.core.dialect.HsqlDbDialect; -import org.springframework.data.relational.core.dialect.MariaDbDialect; -import org.springframework.data.relational.core.dialect.OracleDialect; import org.springframework.data.relational.core.sql.IdentifierProcessing; import org.springframework.data.util.Optionals; import org.springframework.jdbc.core.ConnectionCallback; @@ -50,6 +51,7 @@ * available {@link JdbcDialectProvider extensions}. * * @author Jens Schauder + * @author Mikhail Polivakha * @since 2.0 * @see Dialect * @see SpringFactoriesLoader @@ -109,23 +111,23 @@ public Optional getDialect(JdbcOperations operations) { } @Nullable - private static Dialect getDialect(Connection connection) throws SQLException { + private static JdbcDialect getDialect(Connection connection) throws SQLException { DatabaseMetaData metaData = connection.getMetaData(); String name = metaData.getDatabaseProductName().toLowerCase(Locale.ENGLISH); if (name.contains("hsql")) { - return HsqlDbDialect.INSTANCE; + return JdbcHsqlDbDialect.INSTANCE; } if (name.contains("h2")) { - return H2Dialect.INSTANCE; + return JdbcH2Dialect.INSTANCE; } if (name.contains("mysql")) { return new JdbcMySqlDialect(getIdentifierProcessing(metaData)); } if (name.contains("mariadb")) { - return new MariaDbDialect(getIdentifierProcessing(metaData)); + return new JdbcMariaDbDialect(getIdentifierProcessing(metaData)); } if (name.contains("postgresql")) { return JdbcPostgresDialect.INSTANCE; @@ -137,7 +139,7 @@ private static Dialect getDialect(Connection connection) throws SQLException { return JdbcDb2Dialect.INSTANCE; } if (name.contains("oracle")) { - return OracleDialect.INSTANCE; + return JdbcOracleDialect.INSTANCE; } LOG.info(String.format("Couldn't determine Dialect for \"%s\"", name)); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java index 9f3bd72fd7..99eb539870 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategyUnitTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.annotation.Id; +import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.conversion.IdValueSource; import org.springframework.data.relational.core.dialect.Dialect; @@ -58,7 +59,7 @@ class DefaultDataAccessStrategyUnitTests { void before() { DelegatingDataAccessStrategy relationResolver = new DelegatingDataAccessStrategy(); - Dialect dialect = HsqlDbDialect.INSTANCE; + Dialect dialect = JdbcHsqlDbDialect.INSTANCE; converter = new MappingJdbcConverter(context, relationResolver, new JdbcCustomConversions(), new DefaultJdbcTypeFactory(jdbcOperations)); accessStrategy = new DataAccessStrategyFactory( // diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java index 240d47f596..d2932931f0 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java @@ -15,10 +15,11 @@ */ package org.springframework.data.jdbc.core.convert; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.UUID; @@ -27,12 +28,11 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; - import org.springframework.data.annotation.Id; +import org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect; +import org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.relational.core.conversion.MutableAggregateChange; -import org.springframework.data.relational.core.dialect.MySqlDialect; -import org.springframework.data.relational.core.dialect.PostgresDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.Sequence; import org.springframework.data.relational.core.mapping.Table; @@ -56,7 +56,7 @@ class IdGeneratingEntityCallbackTest { void setUp() { relationalMappingContext = new RelationalMappingContext(); - relationalMappingContext.setSimpleTypeHolder(new SimpleTypeHolder(PostgresDialect.INSTANCE.simpleTypes(), true)); + relationalMappingContext.setSimpleTypeHolder(new SimpleTypeHolder(JdbcPostgresDialect.INSTANCE.simpleTypes(), true)); } @Test // GH-1923 @@ -65,7 +65,7 @@ void sequenceGenerationIsNotSupported() { NamedParameterJdbcOperations operations = mock(NamedParameterJdbcOperations.class); IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, - MySqlDialect.INSTANCE, operations); + JdbcMySqlDialect.INSTANCE, operations); EntityWithSequence processed = (EntityWithSequence) subject.onBeforeSave(new EntityWithSequence(), MutableAggregateChange.forSave(new EntityWithSequence())); @@ -77,7 +77,7 @@ void sequenceGenerationIsNotSupported() { void entityIsNotMarkedWithTargetSequence() { IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, - MySqlDialect.INSTANCE, operations); + JdbcMySqlDialect.INSTANCE, operations); NoSequenceEntity processed = (NoSequenceEntity) subject.onBeforeSave(new NoSequenceEntity(), MutableAggregateChange.forSave(new NoSequenceEntity())); @@ -93,7 +93,7 @@ void entityIdIsPopulatedFromSequence() { .thenReturn(generatedId); IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, - PostgresDialect.INSTANCE, operations); + JdbcPostgresDialect.INSTANCE, operations); EntityWithSequence processed = (EntityWithSequence) subject.onBeforeSave(new EntityWithSequence(), MutableAggregateChange.forSave(new EntityWithSequence())); @@ -109,7 +109,7 @@ void appliesIntegerConversion() { .thenReturn(generatedId); IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, - PostgresDialect.INSTANCE, operations); + JdbcPostgresDialect.INSTANCE, operations); EntityWithIntSequence processed = (EntityWithIntSequence) subject.onBeforeSave(new EntityWithIntSequence(), MutableAggregateChange.forSave(new EntityWithIntSequence())); @@ -125,7 +125,7 @@ void assignsUuidValues() { .thenReturn(generatedId); IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, - PostgresDialect.INSTANCE, operations); + JdbcPostgresDialect.INSTANCE, operations); EntityWithUuidSequence processed = (EntityWithUuidSequence) subject.onBeforeSave(new EntityWithUuidSequence(), MutableAggregateChange.forSave(new EntityWithUuidSequence())); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/NonQuotingDialect.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/NonQuotingDialect.java index edf150ab16..fda4f5d932 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/NonQuotingDialect.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/NonQuotingDialect.java @@ -15,6 +15,7 @@ */ package org.springframework.data.jdbc.core.convert; +import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; import org.springframework.data.relational.core.dialect.AbstractDialect; import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.dialect.HsqlDbDialect; @@ -38,12 +39,12 @@ private NonQuotingDialect() {} @Override public LimitClause limit() { - return HsqlDbDialect.INSTANCE.limit(); + return JdbcHsqlDbDialect.INSTANCE.limit(); } @Override public LockClause lock() { - return HsqlDbDialect.INSTANCE.lock(); + return JdbcHsqlDbDialect.INSTANCE.lock(); } @Override diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java index d095b27ccb..cc264cbe62 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlGeneratorUnitTests.java @@ -15,11 +15,17 @@ */ package org.springframework.data.jdbc.core.convert; -import static java.util.Collections.*; -import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.SoftAssertions.*; -import static org.springframework.data.relational.core.mapping.ForeignKeyNaming.*; -import static org.springframework.data.relational.core.sql.SqlIdentifier.*; +import static java.util.Collections.emptySet; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.entry; +import static org.assertj.core.api.SoftAssertions.assertSoftly; +import static org.springframework.data.relational.core.mapping.ForeignKeyNaming.APPLY_RENAMING; +import static org.springframework.data.relational.core.mapping.ForeignKeyNaming.IGNORE_RENAMING; +import static org.springframework.data.relational.core.sql.SqlIdentifier.EMPTY; +import static org.springframework.data.relational.core.sql.SqlIdentifier.quoted; +import static org.springframework.data.relational.core.sql.SqlIdentifier.unquoted; import java.util.Map; import java.util.Set; @@ -33,13 +39,13 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils; +import org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect; +import org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect; import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.relational.core.dialect.AnsiDialect; import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.dialect.PostgresDialect; -import org.springframework.data.relational.core.dialect.SqlServerDialect; import org.springframework.data.relational.core.mapping.AggregatePath; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.DefaultNamingStrategy; @@ -274,7 +280,7 @@ void findAllSortedByMultipleFields() { @Test // GH-821 void findAllSortedWithNullHandling_resolvesNullHandlingWhenDialectSupportsIt() { - SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, PostgresDialect.INSTANCE); + SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, JdbcPostgresDialect.INSTANCE); String sql = sqlGenerator .getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST))); @@ -285,7 +291,7 @@ void findAllSortedWithNullHandling_resolvesNullHandlingWhenDialectSupportsIt() { @Test // GH-821 void findAllSortedWithNullHandling_ignoresNullHandlingWhenDialectDoesNotSupportIt() { - SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, SqlServerDialect.INSTANCE); + SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, JdbcSqlServerDialect.INSTANCE); String sql = sqlGenerator .getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST))); @@ -512,7 +518,7 @@ void updateWithVersion() { @Test // DATAJDBC-264 void getInsertForEmptyColumnListPostgres() { - SqlGenerator sqlGenerator = createSqlGenerator(IdOnlyEntity.class, PostgresDialect.INSTANCE); + SqlGenerator sqlGenerator = createSqlGenerator(IdOnlyEntity.class, JdbcPostgresDialect.INSTANCE); String insert = sqlGenerator.getInsert(emptySet()); @@ -522,7 +528,7 @@ void getInsertForEmptyColumnListPostgres() { @Test // GH-777 void gerInsertForEmptyColumnListMsSqlServer() { - SqlGenerator sqlGenerator = createSqlGenerator(IdOnlyEntity.class, SqlServerDialect.INSTANCE); + SqlGenerator sqlGenerator = createSqlGenerator(IdOnlyEntity.class, JdbcSqlServerDialect.INSTANCE); String insert = sqlGenerator.getInsert(emptySet()); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java index 5026385e8d..c5dd57d8e0 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java @@ -15,9 +15,7 @@ */ package org.springframework.data.jdbc.mybatis; -import static org.assertj.core.api.Assertions.*; - -import junit.framework.AssertionFailedError; +import static org.assertj.core.api.Assertions.assertThat; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; @@ -31,18 +29,20 @@ import org.springframework.context.annotation.Primary; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; +import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; 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.TestClass; import org.springframework.data.jdbc.testing.TestConfiguration; -import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; +import junit.framework.AssertionFailedError; + /** * Tests the integration with Mybatis. * @@ -119,7 +119,7 @@ DataAccessStrategy dataAccessStrategy(RelationalMappingContext context, JdbcConv SqlSession sqlSession, EmbeddedDatabase db) { return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, converter, - new NamedParameterJdbcTemplate(db), sqlSession, HsqlDbDialect.INSTANCE); + new NamedParameterJdbcTemplate(db), sqlSession, JdbcHsqlDbDialect.INSTANCE); } } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java index 8c306fea03..2670ed88be 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/DeclaredQueryRepositoryUnitTests.java @@ -16,8 +16,11 @@ package org.springframework.data.jdbc.repository; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; @@ -30,11 +33,11 @@ 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.dialect.JdbcHsqlDbDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.repository.CrudRepository; @@ -93,7 +96,7 @@ private String query() { private @NotNull T repository(Class repositoryInterface) { - Dialect dialect = HsqlDbDialect.INSTANCE; + Dialect dialect = JdbcHsqlDbDialect.INSTANCE; RelationalMappingContext context = new JdbcMappingContext(); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java index 975c354cb5..e15ce6b68f 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java @@ -15,11 +15,16 @@ */ package org.springframework.data.jdbc.repository; -import static java.util.Arrays.*; -import static org.assertj.core.api.Assertions.*; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashMap; @@ -33,13 +38,21 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.data.jdbc.core.convert.*; +import org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy; +import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory; +import org.springframework.data.jdbc.core.convert.DelegatingDataAccessStrategy; +import org.springframework.data.jdbc.core.convert.InsertStrategyFactory; +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.SqlGeneratorSource; +import org.springframework.data.jdbc.core.convert.SqlParametersFactory; +import org.springframework.data.jdbc.core.dialect.JdbcH2Dialect; +import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository; import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.dialect.H2Dialect; -import org.springframework.data.relational.core.dialect.HsqlDbDialect; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.event.AfterConvertEvent; import org.springframework.data.relational.core.mapping.event.AfterDeleteEvent; @@ -86,7 +99,7 @@ void before() { RelationalMappingContext context = new JdbcMappingContext(); NamedParameterJdbcOperations operations = createIdGeneratingOperations(); - Dialect dialect = HsqlDbDialect.INSTANCE; + Dialect dialect = JdbcHsqlDbDialect.INSTANCE; DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy(); JdbcConverter converter = new MappingJdbcConverter(context, delegatingDataAccessStrategy, new JdbcCustomConversions(), new DefaultJdbcTypeFactory(operations.getJdbcOperations())); @@ -100,7 +113,7 @@ void before() { doReturn(true).when(dataAccessStrategy).update(any(), any()); JdbcRepositoryFactory factory = new JdbcRepositoryFactory(dataAccessStrategy, context, converter, - H2Dialect.INSTANCE, publisher, operations); + JdbcH2Dialect.INSTANCE, publisher, operations); this.repository = factory.getRepository(DummyEntityRepository.class); } 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 4638726a0d..b0ad7a4b1a 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 @@ -26,6 +26,7 @@ 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.JdbcHsqlDbDialect; import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy; import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.dialect.HsqlDbDialect; @@ -70,7 +71,7 @@ public static class MyBatisJdbcConfigurationUnderTest extends MyBatisJdbcConfigu @Override @Bean public Dialect jdbcDialect(NamedParameterJdbcOperations operations) { - return HsqlDbDialect.INSTANCE; + return JdbcHsqlDbDialect.INSTANCE; } } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java index 27f4a47c29..a941d1830c 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java @@ -33,6 +33,7 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.MappingJdbcConverter; import org.springframework.data.jdbc.core.convert.RelationResolver; +import org.springframework.data.jdbc.core.dialect.JdbcH2Dialect; import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; @@ -669,7 +670,7 @@ public void createsQueryForCountProjection() throws Exception { } private PartTreeJdbcQuery createQuery(JdbcQueryMethod queryMethod) { - return new PartTreeJdbcQuery(mappingContext, queryMethod, H2Dialect.INSTANCE, converter, + return new PartTreeJdbcQuery(mappingContext, queryMethod, JdbcH2Dialect.INSTANCE, converter, mock(NamedParameterJdbcOperations.class), mock(RowMapper.class)); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java index 7b70956890..80ec8594b4 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java @@ -30,6 +30,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.jdbc.core.convert.JdbcConverter; +import org.springframework.data.jdbc.core.dialect.JdbcH2Dialect; import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.config.DefaultQueryMappingConfiguration; import org.springframework.data.jdbc.repository.query.Query; @@ -138,7 +139,7 @@ void correctLookUpStrategyForKey(QueryLookupStrategy.Key key, Class expectedClas .registerRowMapper(NumberFormat.class, numberFormatMapper); QueryLookupStrategy queryLookupStrategy = JdbcQueryLookupStrategy.create(key, publisher, callbacks, mappingContext, - converter, H2Dialect.INSTANCE, mappingConfiguration, operations, null, ValueExpressionDelegate.create()); + converter, JdbcH2Dialect.INSTANCE, mappingConfiguration, operations, null, ValueExpressionDelegate.create()); assertThat(queryLookupStrategy).isInstanceOf(expectedClass); } @@ -158,7 +159,7 @@ private RepositoryQuery getRepositoryQuery(QueryLookupStrategy.Key key, String n QueryMappingConfiguration mappingConfiguration) { QueryLookupStrategy queryLookupStrategy = JdbcQueryLookupStrategy.create(key, publisher, callbacks, mappingContext, - converter, H2Dialect.INSTANCE, mappingConfiguration, operations, null, ValueExpressionDelegate.create()); + converter, JdbcH2Dialect.INSTANCE, mappingConfiguration, operations, null, ValueExpressionDelegate.create()); Method method = ReflectionUtils.findMethod(MyRepository.class, name); return queryLookupStrategy.resolveQuery(method, metadata, projectionFactory, namedQueries); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Db2Dialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Db2Dialect.java index 726016cfbb..4f21291a12 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Db2Dialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Db2Dialect.java @@ -32,7 +32,10 @@ public class Db2Dialect extends AbstractDialect { /** * Singleton instance. + * + * @deprecated use the {@code org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect} directly. */ + @Deprecated(forRemoval = true) public static final Db2Dialect INSTANCE = new Db2Dialect(); private static final IdGeneration ID_GENERATION = new IdGeneration() { @@ -43,6 +46,7 @@ public boolean supportedForBatchOperations() { @Override public String createSequenceQuery(SqlIdentifier sequenceName) { + /* * This workaround (non-ANSI SQL way of querying sequence) exists for the same reasons it exists for {@link HsqlDbDialect} * diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java index aaab1cb745..73a505e01b 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java @@ -38,8 +38,13 @@ public class H2Dialect extends AbstractDialect { /** * Singleton instance. + * + * @deprecated use either the {@code org.springframework.data.r2dbc.dialect.H2Dialect} or + * {@code org.springframework.data.jdbc.core.dialect.JdbcH2Dialect}. */ + @Deprecated(forRemoval = true) public static final H2Dialect INSTANCE = new H2Dialect(); + private static final IdentifierProcessing IDENTIFIER_PROCESSING = IdentifierProcessing.create(Quoting.ANSI, LetterCasing.UPPER_CASE); private static final IdGeneration ID_GENERATION = IdGeneration.create(IDENTIFIER_PROCESSING); @@ -86,7 +91,7 @@ public ArrayColumns getArraySupport() { return ARRAY_COLUMNS; } - static class H2ArrayColumns implements ArrayColumns { + protected static class H2ArrayColumns implements ArrayColumns { @Override public boolean isSupported() { diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java index d893bffcf7..d3101168e9 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java @@ -26,6 +26,10 @@ */ public class HsqlDbDialect extends AbstractDialect { + /** + * @deprecated use the {@code org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect} directly. + */ + @Deprecated(forRemoval = true) public static final HsqlDbDialect INSTANCE = new HsqlDbDialect(); protected HsqlDbDialect() {} diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java index bb3c3700d2..7d1c929fcc 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/MySqlDialect.java @@ -43,7 +43,11 @@ public class MySqlDialect extends AbstractDialect { /** * Singleton instance. + * + * @deprecated use either the {@code org.springframework.data.r2dbc.dialect.MySqlDialect} or + * {@code org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect} */ + @Deprecated(forRemoval = true) public static final MySqlDialect INSTANCE = new MySqlDialect(); private final IdentifierProcessing identifierProcessing; diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/OracleDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/OracleDialect.java index 7f65461093..371ed852bb 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/OracleDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/OracleDialect.java @@ -15,7 +15,7 @@ */ package org.springframework.data.relational.core.dialect; -import static java.util.Arrays.*; +import static java.util.Arrays.asList; import java.util.Collection; @@ -35,7 +35,11 @@ public class OracleDialect extends AnsiDialect { /** * Singleton instance. + * + * @deprecated use either the {@code org.springframework.data.r2dbc.dialect.OracleDialect} or + * {@code org.springframework.data.jdbc.core.dialect.JdbcOracleDialect}. */ + @Deprecated(forRemoval = true) public static final OracleDialect INSTANCE = new OracleDialect(); private static final IdGeneration ID_GENERATION = new IdGeneration() { diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java index 6979c365e9..a06b4e3b25 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/PostgresDialect.java @@ -49,14 +49,19 @@ public class PostgresDialect extends AbstractDialect { /** * Singleton instance. + * + * @deprecated use either the {@code org.springframework.data.r2dbc.dialect.PostgresDialect} or + * {@code org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect}. */ + @Deprecated(forRemoval = true) public static final PostgresDialect INSTANCE = new PostgresDialect(); private static final Set> POSTGRES_SIMPLE_TYPES = Set.of(UUID.class, URL.class, URI.class, InetAddress.class, Map.class); - private IdentifierProcessing identifierProcessing = IdentifierProcessing.create(Quoting.ANSI, + private static final IdentifierProcessing identifierProcessing = IdentifierProcessing.create(Quoting.ANSI, LetterCasing.LOWER_CASE); + private IdGeneration idGeneration = new IdGeneration() { @Override diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java index 36f0381f84..ad3b706158 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SqlServerDialect.java @@ -34,7 +34,11 @@ public class SqlServerDialect extends AbstractDialect { /** * Singleton instance. + * + * @deprecated use either the {@code org.springframework.data.r2dbc.dialect.SqlServerDialect} or + * {@code org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect}. */ + @Deprecated(forRemoval = true) public static final SqlServerDialect INSTANCE = new SqlServerDialect(); private static final IdentifierProcessing IDENTIFIER_PROCESSING = IdentifierProcessing diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java index 17d3ef771d..b03eb034a0 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/HsqlDbDialectUnitTests.java @@ -15,14 +15,14 @@ */ package org.springframework.data.relational.core.dialect; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + import org.junit.jupiter.api.Test; import org.springframework.data.relational.core.sql.From; import org.springframework.data.relational.core.sql.LockMode; import org.springframework.data.relational.core.sql.LockOptions; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - /** * Unit tests for the {@link HsqlDbDialect}. * @@ -34,7 +34,7 @@ public class HsqlDbDialectUnitTests { @Test // DATAJDBC-386 public void shouldNotSupportArrays() { - ArrayColumns arrayColumns = HsqlDbDialect.INSTANCE.getArraySupport(); + ArrayColumns arrayColumns = new HsqlDbDialect().getArraySupport(); assertThat(arrayColumns.isSupported()).isFalse(); } @@ -42,7 +42,7 @@ public void shouldNotSupportArrays() { @Test // DATAJDBC-386 public void shouldRenderLimit() { - LimitClause limit = HsqlDbDialect.INSTANCE.limit(); + LimitClause limit = new HsqlDbDialect().limit(); assertThat(limit.getClausePosition()).isEqualTo(LimitClause.Position.AFTER_ORDER_BY); assertThat(limit.getLimit(10)).isEqualTo("LIMIT 10"); @@ -51,7 +51,7 @@ public void shouldRenderLimit() { @Test // DATAJDBC-386 public void shouldRenderOffset() { - LimitClause limit = HsqlDbDialect.INSTANCE.limit(); + LimitClause limit = new HsqlDbDialect().limit(); assertThat(limit.getOffset(10)).isEqualTo("OFFSET 10"); } @@ -59,7 +59,7 @@ public void shouldRenderOffset() { @Test // DATAJDBC-386 public void shouldRenderLimitOffset() { - LimitClause limit = HsqlDbDialect.INSTANCE.limit(); + LimitClause limit = new HsqlDbDialect().limit(); assertThat(limit.getLimitOffset(20, 10)).isEqualTo("OFFSET 10 LIMIT 20"); } @@ -67,7 +67,7 @@ public void shouldRenderLimitOffset() { @Test // DATAJDBC-386 public void shouldQuoteIdentifiersUsingBackticks() { - String abcQuoted = HsqlDbDialect.INSTANCE.getIdentifierProcessing().quote("abc"); + String abcQuoted = new HsqlDbDialect().getIdentifierProcessing().quote("abc"); assertThat(abcQuoted).isEqualTo("\"abc\""); } @@ -75,7 +75,7 @@ public void shouldQuoteIdentifiersUsingBackticks() { @Test // DATAJDBC-498 public void shouldRenderLock() { - LockClause limit = HsqlDbDialect.INSTANCE.lock(); + LockClause limit = new HsqlDbDialect().lock(); From from = mock(From.class); LockOptions lockOptions = new LockOptions(LockMode.PESSIMISTIC_WRITE, from); diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectRenderingUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectRenderingUnitTests.java index 96f64c2036..2ad7733412 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectRenderingUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectRenderingUnitTests.java @@ -36,7 +36,7 @@ */ public class MySqlDialectRenderingUnitTests { - private final RenderContextFactory factory = new RenderContextFactory(MySqlDialect.INSTANCE); + private final RenderContextFactory factory = new RenderContextFactory(new MySqlDialect()); @BeforeEach public void before() { diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java index 51736ef0f7..d9112a4dde 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/dialect/MySqlDialectUnitTests.java @@ -35,7 +35,7 @@ public class MySqlDialectUnitTests { @Test // DATAJDBC-278 public void shouldNotSupportArrays() { - ArrayColumns arrayColumns = MySqlDialect.INSTANCE.getArraySupport(); + ArrayColumns arrayColumns = new MySqlDialect().getArraySupport(); assertThat(arrayColumns.isSupported()).isFalse(); } @@ -43,7 +43,7 @@ public void shouldNotSupportArrays() { @Test // DATAJDBC-278 public void shouldRenderLimit() { - LimitClause limit = MySqlDialect.INSTANCE.limit(); + LimitClause limit = new MySqlDialect().limit(); assertThat(limit.getClausePosition()).isEqualTo(LimitClause.Position.AFTER_ORDER_BY); assertThat(limit.getLimit(10)).isEqualTo("LIMIT 10"); @@ -52,7 +52,7 @@ public void shouldRenderLimit() { @Test // DATAJDBC-278 public void shouldRenderOffset() { - LimitClause limit = MySqlDialect.INSTANCE.limit(); + LimitClause limit = new MySqlDialect().limit(); assertThat(limit.getOffset(10)).isEqualTo("LIMIT 10, 18446744073709551615"); } @@ -60,7 +60,7 @@ public void shouldRenderOffset() { @Test // DATAJDBC-278 public void shouldRenderLimitOffset() { - LimitClause limit = MySqlDialect.INSTANCE.limit(); + LimitClause limit = new MySqlDialect().limit(); assertThat(limit.getLimitOffset(20, 10)).isEqualTo("LIMIT 10, 20"); } @@ -68,7 +68,7 @@ public void shouldRenderLimitOffset() { @Test // DATAJDBC-386 public void shouldQuoteIdentifiersUsingBackticks() { - String abcQuoted = MySqlDialect.INSTANCE.getIdentifierProcessing().quote("abc"); + String abcQuoted = new MySqlDialect().getIdentifierProcessing().quote("abc"); assertThat(abcQuoted).isEqualTo("`abc`"); } @@ -76,7 +76,7 @@ public void shouldQuoteIdentifiersUsingBackticks() { @Test // DATAJDBC-498 public void shouldRenderLock() { - LockClause lock = MySqlDialect.INSTANCE.lock(); + LockClause lock = new MySqlDialect().lock(); From from = mock(From.class); assertThat(lock.getLock(new LockOptions(LockMode.PESSIMISTIC_WRITE, from))).isEqualTo("FOR UPDATE"); From b98e32309576ab0cbb9664d143cfe207d9dbe36d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Apr 2025 10:47:04 +0200 Subject: [PATCH 2/2] Polishing. Deprecate original DialectResolver and JdbcArrayColumns as they've been in the wrong package and introduce replacements in the dialect package. Let deprecated types extend from their replacements to retain compatibility. Make instance holders final, fix Javadoc typos, update reference docs. --- .../core/convert/DefaultJdbcTypeFactory.java | 24 +- .../jdbc/core/convert/JdbcArrayColumns.java | 4 +- .../jdbc/core/dialect/DialectResolver.java | 272 ++++++++++++++++++ .../jdbc/core/dialect/JdbcArrayColumns.java | 92 ++++++ .../core/dialect/JdbcArrayColumnsAdapter.java | 38 +++ .../jdbc/core/dialect/JdbcDb2Dialect.java | 2 +- .../data/jdbc/core/dialect/JdbcDialect.java | 2 +- .../data/jdbc/core/dialect/JdbcH2Dialect.java | 12 +- .../jdbc/core/dialect/JdbcHsqlDbDialect.java | 12 +- .../jdbc/core/dialect/JdbcMariaDbDialect.java | 5 +- .../jdbc/core/dialect/JdbcMySqlDialect.java | 5 +- .../jdbc/core/dialect/JdbcOracleDialect.java | 11 +- .../core/dialect/JdbcPostgresDialect.java | 1 - .../core/dialect/JdbcSqlServerDialect.java | 3 +- .../config/AbstractJdbcConfiguration.java | 4 +- .../repository/config/DialectResolver.java | 117 ++------ .../main/resources/META-INF/spring.factories | 2 +- .../data/jdbc/DependencyTests.java | 2 + .../data/jdbc/testing/TestConfiguration.java | 4 +- .../relational/core/dialect/AnsiDialect.java | 4 +- .../relational/core/dialect/H2Dialect.java | 8 +- .../ROOT/pages/jdbc/getting-started.adoc | 6 +- 22 files changed, 489 insertions(+), 141 deletions(-) create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/DialectResolver.java create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumns.java create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumnsAdapter.java diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java index a031e79fd8..040367b06a 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java @@ -33,7 +33,7 @@ public class DefaultJdbcTypeFactory implements JdbcTypeFactory { private final JdbcOperations operations; - private final JdbcArrayColumns arrayColumns; + private final org.springframework.data.jdbc.core.dialect.JdbcArrayColumns arrayColumns; /** * Creates a new {@link DefaultJdbcTypeFactory}. @@ -41,7 +41,7 @@ public class DefaultJdbcTypeFactory implements JdbcTypeFactory { * @param operations must not be {@literal null}. */ public DefaultJdbcTypeFactory(JdbcOperations operations) { - this(operations, JdbcArrayColumns.DefaultSupport.INSTANCE); + this(operations, org.springframework.data.jdbc.core.dialect.JdbcArrayColumns.DefaultSupport.INSTANCE); } /** @@ -49,7 +49,11 @@ public DefaultJdbcTypeFactory(JdbcOperations operations) { * * @param operations must not be {@literal null}. * @since 2.3 + * @deprecated use + * {@link #DefaultJdbcTypeFactory(JdbcOperations, org.springframework.data.jdbc.core.dialect.JdbcArrayColumns)} + * instead. */ + @Deprecated(forRemoval = true, since = "3.5") public DefaultJdbcTypeFactory(JdbcOperations operations, JdbcArrayColumns arrayColumns) { Assert.notNull(operations, "JdbcOperations must not be null"); @@ -59,6 +63,22 @@ public DefaultJdbcTypeFactory(JdbcOperations operations, JdbcArrayColumns arrayC this.arrayColumns = arrayColumns; } + /** + * Creates a new {@link DefaultJdbcTypeFactory}. + * + * @param operations must not be {@literal null}. + * @since 3.5 + */ + public DefaultJdbcTypeFactory(JdbcOperations operations, + org.springframework.data.jdbc.core.dialect.JdbcArrayColumns arrayColumns) { + + Assert.notNull(operations, "JdbcOperations must not be null"); + Assert.notNull(arrayColumns, "JdbcArrayColumns must not be null"); + + this.operations = operations; + this.arrayColumns = arrayColumns; + } + @Override public Array createArray(Object[] value) { diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java index 3086765efc..5f68fbb735 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcArrayColumns.java @@ -26,8 +26,10 @@ * @author Jens Schauder * @author Mark Paluch * @since 2.3 + * @deprecated since 3.5, replacement moved to {@link org.springframework.data.jdbc.core.dialect.JdbcArrayColumns}. */ -public interface JdbcArrayColumns extends ArrayColumns { +@Deprecated(forRemoval = true) +public interface JdbcArrayColumns extends org.springframework.data.jdbc.core.dialect.JdbcArrayColumns { @Override default Class getArrayType(Class userType) { diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/DialectResolver.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/DialectResolver.java new file mode 100644 index 0000000000..21d1433d82 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/DialectResolver.java @@ -0,0 +1,272 @@ +/* + * Copyright 2020-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.core.dialect; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +import javax.sql.DataSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.io.support.SpringFactoriesLoader; +import org.springframework.dao.NonTransientDataAccessException; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.dialect.Escaper; +import org.springframework.data.relational.core.dialect.IdGeneration; +import org.springframework.data.relational.core.dialect.InsertRenderContext; +import org.springframework.data.relational.core.dialect.LimitClause; +import org.springframework.data.relational.core.dialect.LockClause; +import org.springframework.data.relational.core.dialect.OrderByNullPrecedence; +import org.springframework.data.relational.core.sql.IdentifierProcessing; +import org.springframework.data.relational.core.sql.SimpleFunction; +import org.springframework.data.relational.core.sql.render.SelectRenderContext; +import org.springframework.data.util.Optionals; +import org.springframework.jdbc.core.ConnectionCallback; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Resolves a {@link Dialect}. Resolution typically uses {@link JdbcOperations} to obtain and inspect a + * {@link Connection}. Dialect resolution uses Spring's {@link SpringFactoriesLoader spring.factories} to determine + * available {@link JdbcDialectProvider extensions}. + * + * @author Jens Schauder + * @author Mikhail Polivakha + * @since 3.5 + * @see Dialect + * @see SpringFactoriesLoader + */ +public class DialectResolver { + + private static final Log LOG = LogFactory.getLog(DialectResolver.class); + + private static final List DETECTORS = SpringFactoriesLoader + .loadFactories(JdbcDialectProvider.class, DialectResolver.class.getClassLoader()); + + private static final List LEGACY_DETECTORS = SpringFactoriesLoader + .loadFactories(org.springframework.data.jdbc.repository.config.DialectResolver.JdbcDialectProvider.class, + DialectResolver.class.getClassLoader()); + + // utility constructor. + private DialectResolver() {} + + /** + * Retrieve a {@link Dialect} by inspecting a {@link Connection}. + * + * @param operations must not be {@literal null}. + * @return the resolved {@link Dialect} {@link NoDialectException} if the database type cannot be determined from + * {@link DataSource}. + * @throws NoDialectException if no {@link Dialect} can be found. + */ + public static JdbcDialect getDialect(JdbcOperations operations) { + + return Stream.concat(LEGACY_DETECTORS.stream(), DETECTORS.stream()) // + .map(it -> it.getDialect(operations)) // + .flatMap(Optionals::toStream) // + .map(it -> it instanceof JdbcDialect ? (JdbcDialect) it : new JdbcDialectAdapter(it)).findFirst() // + .orElseThrow(() -> new NoDialectException( + String.format("Cannot determine a dialect for %s; Please provide a Dialect", operations))); + } + + /** + * SPI to extend Spring's default JDBC Dialect discovery mechanism. Implementations of this interface are discovered + * through Spring's {@link SpringFactoriesLoader} mechanism. + * + * @author Jens Schauder + * @see SpringFactoriesLoader + */ + public interface JdbcDialectProvider { + + /** + * Returns a {@link Dialect} for a {@link DataSource}. + * + * @param operations the {@link JdbcOperations} to be used with the {@link Dialect}. + * @return {@link Optional} containing the {@link Dialect} if the {@link JdbcDialectProvider} can provide a dialect + * object, otherwise {@link Optional#empty()}. + */ + Optional getDialect(JdbcOperations operations); + } + + public static class DefaultDialectProvider implements JdbcDialectProvider { + + @Override + public Optional getDialect(JdbcOperations operations) { + return Optional.ofNullable(operations.execute((ConnectionCallback) DefaultDialectProvider::getDialect)); + } + + @Nullable + private static JdbcDialect getDialect(Connection connection) throws SQLException { + + DatabaseMetaData metaData = connection.getMetaData(); + + String name = metaData.getDatabaseProductName().toLowerCase(Locale.ENGLISH); + + if (name.contains("hsql")) { + return JdbcHsqlDbDialect.INSTANCE; + } + if (name.contains("h2")) { + return JdbcH2Dialect.INSTANCE; + } + if (name.contains("mysql")) { + return new JdbcMySqlDialect(getIdentifierProcessing(metaData)); + } + if (name.contains("mariadb")) { + return new JdbcMariaDbDialect(getIdentifierProcessing(metaData)); + } + if (name.contains("postgresql")) { + return JdbcPostgresDialect.INSTANCE; + } + if (name.contains("microsoft")) { + return JdbcSqlServerDialect.INSTANCE; + } + if (name.contains("db2")) { + return JdbcDb2Dialect.INSTANCE; + } + if (name.contains("oracle")) { + return JdbcOracleDialect.INSTANCE; + } + + LOG.info(String.format("Couldn't determine Dialect for \"%s\"", name)); + return null; + } + + private static IdentifierProcessing getIdentifierProcessing(DatabaseMetaData metaData) throws SQLException { + + // getIdentifierQuoteString() returns a space " " if identifier quoting is not + // supported. + String quoteString = metaData.getIdentifierQuoteString(); + IdentifierProcessing.Quoting quoting = StringUtils.hasText(quoteString) + ? new IdentifierProcessing.Quoting(quoteString) + : IdentifierProcessing.Quoting.NONE; + + IdentifierProcessing.LetterCasing letterCasing; + // IdentifierProcessing tries to mimic the behavior of unquoted identifiers for their quoted variants. + if (metaData.supportsMixedCaseIdentifiers()) { + letterCasing = IdentifierProcessing.LetterCasing.AS_IS; + } else if (metaData.storesUpperCaseIdentifiers()) { + letterCasing = IdentifierProcessing.LetterCasing.UPPER_CASE; + } else if (metaData.storesLowerCaseIdentifiers()) { + letterCasing = IdentifierProcessing.LetterCasing.LOWER_CASE; + } else { // this shouldn't happen since one of the previous cases should be true. + // But if it does happen, we go with the ANSI default. + letterCasing = IdentifierProcessing.LetterCasing.UPPER_CASE; + } + + return IdentifierProcessing.create(quoting, letterCasing); + } + } + + /** + * Exception thrown when {@link DialectResolver} cannot resolve a {@link Dialect}. + */ + public static class NoDialectException extends NonTransientDataAccessException { + + /** + * Constructor for NoDialectFoundException. + * + * @param msg the detail message + */ + protected NoDialectException(String msg) { + super(msg); + } + } + + private static class JdbcDialectAdapter implements JdbcDialect { + + private final Dialect delegate; + private final JdbcArrayColumnsAdapter arrayColumns; + + public JdbcDialectAdapter(Dialect delegate) { + this.delegate = delegate; + this.arrayColumns = new JdbcArrayColumnsAdapter(delegate.getArraySupport()); + } + + @Override + public LimitClause limit() { + return delegate.limit(); + } + + @Override + public LockClause lock() { + return delegate.lock(); + } + + @Override + public JdbcArrayColumns getArraySupport() { + return arrayColumns; + } + + @Override + public SelectRenderContext getSelectContext() { + return delegate.getSelectContext(); + } + + @Override + public IdentifierProcessing getIdentifierProcessing() { + return delegate.getIdentifierProcessing(); + } + + @Override + public Escaper getLikeEscaper() { + return delegate.getLikeEscaper(); + } + + @Override + public IdGeneration getIdGeneration() { + return delegate.getIdGeneration(); + } + + @Override + public Collection getConverters() { + return delegate.getConverters(); + } + + @Override + public Set> simpleTypes() { + return delegate.simpleTypes(); + } + + @Override + public InsertRenderContext getInsertRenderContext() { + return delegate.getInsertRenderContext(); + } + + @Override + public OrderByNullPrecedence orderByNullHandling() { + return delegate.orderByNullHandling(); + } + + @Override + public SimpleFunction getExistsFunction() { + return delegate.getExistsFunction(); + } + + @Override + public boolean supportsSingleQueryLoading() { + return delegate.supportsSingleQueryLoading(); + } + } + +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumns.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumns.java new file mode 100644 index 0000000000..60568a7ee0 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumns.java @@ -0,0 +1,92 @@ +/* + * Copyright 2021-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.core.dialect; + +import java.sql.SQLType; + +import org.springframework.data.jdbc.support.JdbcUtil; +import org.springframework.data.relational.core.dialect.ArrayColumns; + +/** + * {@link ArrayColumns} that offer JDBC-specific functionality. + * + * @author Jens Schauder + * @author Mark Paluch + * @since 3.5 + */ +public interface JdbcArrayColumns extends ArrayColumns { + + @Override + default Class getArrayType(Class userType) { + return ArrayColumns.unwrapComponentType(userType); + } + + /** + * Determine the {@link SQLType} for a given {@link Class array component type}. + * + * @param componentType component type of the array. + * @return the dialect-supported array type. + * @since 3.1.3 + */ + default SQLType getSqlType(Class componentType) { + return JdbcUtil.targetSqlTypeFor(getArrayType(componentType)); + } + + /** + * The appropriate SQL type as a String which should be used to represent the given {@link SQLType} in an + * {@link java.sql.Array}. Defaults to the name of the argument. + * + * @param jdbcType the {@link SQLType} value representing the type that should be stored in the + * {@link java.sql.Array}. Must not be {@literal null}. + * @return the appropriate SQL type as a String which should be used to represent the given {@link SQLType} in an + * {@link java.sql.Array}. Guaranteed to be not {@literal null}. + */ + default String getArrayTypeName(SQLType jdbcType) { + return jdbcType.getName(); + } + + /** + * Default {@link ArrayColumns} implementation for dialects that do not support array-typed columns. + */ + enum Unsupported implements JdbcArrayColumns { + + INSTANCE; + + @Override + public boolean isSupported() { + return false; + } + + @Override + public String getArrayTypeName(SQLType jdbcType) { + throw new UnsupportedOperationException("Array types not supported"); + } + + } + + /** + * Default {@link ArrayColumns} implementation for dialects that do not support array-typed columns. + */ + enum DefaultSupport implements JdbcArrayColumns { + + INSTANCE; + + @Override + public boolean isSupported() { + return true; + } + } +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumnsAdapter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumnsAdapter.java new file mode 100644 index 0000000000..6a117a2d5f --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcArrayColumnsAdapter.java @@ -0,0 +1,38 @@ +/* + * 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.core.dialect; + +import org.springframework.data.relational.core.dialect.ArrayColumns; + +/** + * Adapter for {@link ArrayColumns} to be exported as {@link JdbcArrayColumns}. + * + * @author Mark Paluch + * @since 3.5 + */ +record JdbcArrayColumnsAdapter(ArrayColumns arrayColumns) implements JdbcArrayColumns { + + @Override + public boolean isSupported() { + return arrayColumns.isSupported(); + } + + @Override + public Class getArrayType(Class userType) { + return arrayColumns.getArrayType(userType); + } + +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java index a627fabe2b..2288a44c18 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDb2Dialect.java @@ -35,7 +35,7 @@ */ public class JdbcDb2Dialect extends Db2Dialect implements JdbcDialect { - public static JdbcDb2Dialect INSTANCE = new JdbcDb2Dialect(); + public static final JdbcDb2Dialect INSTANCE = new JdbcDb2Dialect(); protected JdbcDb2Dialect() {} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java index 8308eb536e..5728ce4f56 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java @@ -15,7 +15,6 @@ */ package org.springframework.data.jdbc.core.dialect; -import org.springframework.data.jdbc.core.convert.JdbcArrayColumns; import org.springframework.data.relational.core.dialect.Dialect; /** @@ -37,4 +36,5 @@ public interface JdbcDialect extends Dialect { default JdbcArrayColumns getArraySupport() { return JdbcArrayColumns.Unsupported.INSTANCE; } + } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java index 34adfff3f2..8f781ef9db 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcH2Dialect.java @@ -13,25 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.jdbc.core.dialect; -import org.springframework.data.jdbc.core.convert.JdbcArrayColumns; import org.springframework.data.relational.core.dialect.H2Dialect; /** - * JDBC specific H2 Dialect. + * JDBC-specific H2 Dialect. * * @author Mikhail Polivakha + * @since 3.5 */ public class JdbcH2Dialect extends H2Dialect implements JdbcDialect { - public static JdbcH2Dialect INSTANCE = new JdbcH2Dialect(); + public static final JdbcH2Dialect INSTANCE = new JdbcH2Dialect(); + + private static final JdbcArrayColumns ARRAY_COLUMNS = new JdbcArrayColumnsAdapter(H2ArrayColumns.INSTANCE); @Override public JdbcArrayColumns getArraySupport() { - return new JdbcH2ArrayColumns(); + return ARRAY_COLUMNS; } - public static class JdbcH2ArrayColumns extends H2ArrayColumns implements JdbcArrayColumns { } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java index ef64bdce21..77f7531edc 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcHsqlDbDialect.java @@ -13,17 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.jdbc.core.dialect; import org.springframework.data.relational.core.dialect.HsqlDbDialect; /** - * JDBC specific HsqlDB Dialect. + * JDBC-specific HsqlDB Dialect. * * @author Mikhail Polivakha + * @since 3.5 */ public class JdbcHsqlDbDialect extends HsqlDbDialect implements JdbcDialect { - public static JdbcHsqlDbDialect INSTANCE = new JdbcHsqlDbDialect(); + public static final JdbcHsqlDbDialect INSTANCE = new JdbcHsqlDbDialect(); + + @Override + public JdbcArrayColumns getArraySupport() { + return JdbcArrayColumns.DefaultSupport.INSTANCE; + } + } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java index 676c11a8bc..16c416f736 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMariaDbDialect.java @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.jdbc.core.dialect; import org.springframework.data.relational.core.dialect.MariaDbDialect; import org.springframework.data.relational.core.sql.IdentifierProcessing; /** - * JDBC specific MariaDb Dialect. + * JDBC-specific MariaDb Dialect. * * @author Mikhail Polivakha + * @since 3.5 */ public class JdbcMariaDbDialect extends MariaDbDialect implements JdbcDialect { public JdbcMariaDbDialect(IdentifierProcessing identifierProcessing) { super(identifierProcessing); } + } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java index 90529bef0a..76079db6a4 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcMySqlDialect.java @@ -28,13 +28,12 @@ import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.data.jdbc.core.mapping.JdbcValue; -import org.springframework.data.relational.core.dialect.Db2Dialect; import org.springframework.data.relational.core.dialect.MySqlDialect; import org.springframework.data.relational.core.sql.IdentifierProcessing; import org.springframework.lang.NonNull; /** - * {@link Db2Dialect} that registers JDBC specific converters. + * {@link MySqlDialect} that registers JDBC specific converters. * * @author Jens Schauder * @author Christoph Strobl @@ -43,7 +42,7 @@ */ public class JdbcMySqlDialect extends MySqlDialect implements JdbcDialect { - public static JdbcMySqlDialect INSTANCE = new JdbcMySqlDialect(); + public static final JdbcMySqlDialect INSTANCE = new JdbcMySqlDialect(); public JdbcMySqlDialect(IdentifierProcessing identifierProcessing) { super(identifierProcessing); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java index 86dd5ee147..3b0b40cce9 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcOracleDialect.java @@ -16,24 +16,23 @@ package org.springframework.data.jdbc.core.dialect; -import org.springframework.data.jdbc.core.convert.JdbcArrayColumns; -import org.springframework.data.relational.core.dialect.ArrayColumns; import org.springframework.data.relational.core.dialect.ObjectArrayColumns; import org.springframework.data.relational.core.dialect.OracleDialect; /** - * JDBC specific Oracle Dialect. + * JDBC-specific Oracle Dialect. * * @author Mikhail Polivakha */ public class JdbcOracleDialect extends OracleDialect implements JdbcDialect { - public static JdbcOracleDialect INSTANCE = new JdbcOracleDialect(); + public static final JdbcOracleDialect INSTANCE = new JdbcOracleDialect(); + + private static final JdbcArrayColumns ARRAY_COLUMNS = new JdbcArrayColumnsAdapter(ObjectArrayColumns.INSTANCE); @Override public JdbcArrayColumns getArraySupport() { - return new JdbcOracleArrayColumns(); + return ARRAY_COLUMNS; } - public static class JdbcOracleArrayColumns extends ObjectArrayColumns implements JdbcArrayColumns { } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialect.java index 24f5a69ae7..b2c9b91626 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialect.java @@ -33,7 +33,6 @@ import org.postgresql.core.Oid; import org.postgresql.jdbc.TypeInfoCache; -import org.springframework.data.jdbc.core.convert.JdbcArrayColumns; import org.springframework.data.relational.core.dialect.PostgresDialect; import org.springframework.util.ClassUtils; diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java index d3d431ec4e..bc45ad3dda 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialect.java @@ -37,7 +37,7 @@ */ public class JdbcSqlServerDialect extends SqlServerDialect implements JdbcDialect { - public static JdbcSqlServerDialect INSTANCE = new JdbcSqlServerDialect(); + public static final JdbcSqlServerDialect INSTANCE = new JdbcSqlServerDialect(); @Override public Collection getConverters() { @@ -69,4 +69,5 @@ public Instant convert(DateTimeOffset source) { return source.getOffsetDateTime().toInstant(); } } + } 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 ac4483069e..af7c3352e1 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 @@ -38,6 +38,7 @@ 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.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; @@ -146,7 +147,8 @@ public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingCont public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations, @Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, Dialect dialect) { - JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect ? ((JdbcDialect) dialect).getArraySupport() + org.springframework.data.jdbc.core.dialect.JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect + ? ((JdbcDialect) dialect).getArraySupport() : JdbcArrayColumns.DefaultSupport.INSTANCE; DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns); 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/repository/config/DialectResolver.java index 21a4c44021..1f81381741 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/repository/config/DialectResolver.java @@ -16,34 +16,14 @@ package org.springframework.data.jdbc.repository.config; import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; -import java.util.List; -import java.util.Locale; import java.util.Optional; import javax.sql.DataSource; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.dao.NonTransientDataAccessException; -import org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect; import org.springframework.data.jdbc.core.dialect.JdbcDialect; -import org.springframework.data.jdbc.core.dialect.JdbcH2Dialect; -import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect; -import org.springframework.data.jdbc.core.dialect.JdbcMariaDbDialect; -import org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect; -import org.springframework.data.jdbc.core.dialect.JdbcOracleDialect; -import org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect; -import org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect; import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.sql.IdentifierProcessing; -import org.springframework.data.util.Optionals; -import org.springframework.jdbc.core.ConnectionCallback; import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.lang.Nullable; -import org.springframework.util.StringUtils; /** * Resolves a {@link Dialect}. Resolution typically uses {@link JdbcOperations} to obtain and inspect a @@ -55,14 +35,12 @@ * @since 2.0 * @see Dialect * @see SpringFactoriesLoader + * @deprecated since 3.5, replacement {@link org.springframework.data.jdbc.core.dialect.DialectResolver} was moved to + * the {@link org.springframework.data.jdbc.core.dialect} package. */ +@Deprecated(since = "3.5", forRemoval = true) public class DialectResolver { - private static final Log LOG = LogFactory.getLog(DialectResolver.class); - - private static final List DETECTORS = SpringFactoriesLoader - .loadFactories(JdbcDialectProvider.class, DialectResolver.class.getClassLoader()); - // utility constructor. private DialectResolver() {} @@ -74,14 +52,8 @@ private DialectResolver() {} * {@link DataSource}. * @throws NoDialectException if no {@link Dialect} can be found. */ - public static Dialect getDialect(JdbcOperations operations) { - - return DETECTORS.stream() // - .map(it -> it.getDialect(operations)) // - .flatMap(Optionals::toStream) // - .findFirst() // - .orElseThrow(() -> new NoDialectException( - String.format("Cannot determine a dialect for %s; Please provide a Dialect", operations))); + public static JdbcDialect getDialect(JdbcOperations operations) { + return org.springframework.data.jdbc.core.dialect.DialectResolver.getDialect(operations); } /** @@ -90,8 +62,12 @@ public static Dialect getDialect(JdbcOperations operations) { * * @author Jens Schauder * @see org.springframework.core.io.support.SpringFactoriesLoader + * @deprecated since 3.5, replacement {@link org.springframework.data.jdbc.core.dialect.DialectResolver} was moved to + * the {@link org.springframework.data.jdbc.core.dialect} package. */ - public interface JdbcDialectProvider { + @Deprecated(since = "3.5", forRemoval = true) + public interface JdbcDialectProvider + extends org.springframework.data.jdbc.core.dialect.DialectResolver.JdbcDialectProvider { /** * Returns a {@link Dialect} for a {@link DataSource}. @@ -103,79 +79,18 @@ public interface JdbcDialectProvider { Optional getDialect(JdbcOperations operations); } - static public class DefaultDialectProvider implements JdbcDialectProvider { - - @Override - public Optional getDialect(JdbcOperations operations) { - return Optional.ofNullable(operations.execute((ConnectionCallback) DefaultDialectProvider::getDialect)); - } - - @Nullable - private static JdbcDialect getDialect(Connection connection) throws SQLException { - - DatabaseMetaData metaData = connection.getMetaData(); - - String name = metaData.getDatabaseProductName().toLowerCase(Locale.ENGLISH); + @Deprecated(since = "3.5", forRemoval = true) + static public class DefaultDialectProvider extends + org.springframework.data.jdbc.core.dialect.DialectResolver.DefaultDialectProvider implements JdbcDialectProvider { - if (name.contains("hsql")) { - return JdbcHsqlDbDialect.INSTANCE; - } - if (name.contains("h2")) { - return JdbcH2Dialect.INSTANCE; - } - if (name.contains("mysql")) { - return new JdbcMySqlDialect(getIdentifierProcessing(metaData)); - } - if (name.contains("mariadb")) { - return new JdbcMariaDbDialect(getIdentifierProcessing(metaData)); - } - if (name.contains("postgresql")) { - return JdbcPostgresDialect.INSTANCE; - } - if (name.contains("microsoft")) { - return JdbcSqlServerDialect.INSTANCE; - } - if (name.contains("db2")) { - return JdbcDb2Dialect.INSTANCE; - } - if (name.contains("oracle")) { - return JdbcOracleDialect.INSTANCE; - } - - LOG.info(String.format("Couldn't determine Dialect for \"%s\"", name)); - return null; - } - - private static IdentifierProcessing getIdentifierProcessing(DatabaseMetaData metaData) throws SQLException { - - // getIdentifierQuoteString() returns a space " " if identifier quoting is not - // supported. - String quoteString = metaData.getIdentifierQuoteString(); - IdentifierProcessing.Quoting quoting = StringUtils.hasText(quoteString) - ? new IdentifierProcessing.Quoting(quoteString) - : IdentifierProcessing.Quoting.NONE; - - IdentifierProcessing.LetterCasing letterCasing; - // IdentifierProcessing tries to mimic the behavior of unquoted identifiers for their quoted variants. - if (metaData.supportsMixedCaseIdentifiers()) { - letterCasing = IdentifierProcessing.LetterCasing.AS_IS; - } else if (metaData.storesUpperCaseIdentifiers()) { - letterCasing = IdentifierProcessing.LetterCasing.UPPER_CASE; - } else if (metaData.storesLowerCaseIdentifiers()) { - letterCasing = IdentifierProcessing.LetterCasing.LOWER_CASE; - } else { // this shouldn't happen since one of the previous cases should be true. - // But if it does happen, we go with the ANSI default. - letterCasing = IdentifierProcessing.LetterCasing.UPPER_CASE; - } - - return IdentifierProcessing.create(quoting, letterCasing); - } } /** * Exception thrown when {@link DialectResolver} cannot resolve a {@link Dialect}. */ - public static class NoDialectException extends NonTransientDataAccessException { + @Deprecated(since = "3.5", forRemoval = true) + public static class NoDialectException + extends org.springframework.data.jdbc.core.dialect.DialectResolver.NoDialectException { /** * Constructor for NoDialectFoundException. 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..dedc6fdf90 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.core.dialect.DialectResolver$JdbcDialectProvider=org.springframework.data.jdbc.core.dialect.DialectResolver.DefaultDialectProvider diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java index b754581659..d7d142b4a8 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java @@ -16,6 +16,7 @@ package org.springframework.data.jdbc; import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.data.auditing.config.AuditingHandlerBeanDefinitionParser; @@ -34,6 +35,7 @@ * * @author Jens Schauder */ +@Disabled("Disabled because of JdbcArrayColumns and Dialect cycle to be resolved in 4.0") public class DependencyTests { @Test 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 ea3e5482cf..0767c2ee73 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 @@ -37,6 +37,7 @@ import org.springframework.context.annotation.Profile; import org.springframework.data.convert.CustomConversions; import org.springframework.data.jdbc.core.convert.*; +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; @@ -169,7 +170,8 @@ JdbcConverter relationalConverter(RelationalMappingContext mappingContext, @Lazy CustomConversions conversions, @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, Dialect dialect) { - JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect ? + org.springframework.data.jdbc.core.dialect.JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect + ? ((JdbcDialect) dialect).getArraySupport() : JdbcArrayColumns.DefaultSupport.INSTANCE; diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/AnsiDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/AnsiDialect.java index 044d0f62b0..f9c713bc47 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/AnsiDialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/AnsiDialect.java @@ -70,8 +70,6 @@ public Position getClausePosition() { } }; - private final ArrayColumns ARRAY_COLUMNS = ObjectArrayColumns.INSTANCE; - @Override public LimitClause limit() { return LIMIT_CLAUSE; @@ -84,7 +82,7 @@ public LockClause lock() { @Override public ArrayColumns getArraySupport() { - return ARRAY_COLUMNS; + return ObjectArrayColumns.INSTANCE; } @Override diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java index 73a505e01b..24677ccbb6 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java @@ -49,8 +49,6 @@ public class H2Dialect extends AbstractDialect { LetterCasing.UPPER_CASE); private static final IdGeneration ID_GENERATION = IdGeneration.create(IDENTIFIER_PROCESSING); - protected H2Dialect() {} - private static final LimitClause LIMIT_CLAUSE = new LimitClause() { @Override @@ -74,7 +72,7 @@ public Position getClausePosition() { } }; - private final H2ArrayColumns ARRAY_COLUMNS = new H2ArrayColumns(); + protected H2Dialect() {} @Override public LimitClause limit() { @@ -88,11 +86,13 @@ public LockClause lock() { @Override public ArrayColumns getArraySupport() { - return ARRAY_COLUMNS; + return H2ArrayColumns.INSTANCE; } protected static class H2ArrayColumns implements ArrayColumns { + public static final H2ArrayColumns INSTANCE = new H2ArrayColumns(); + @Override public boolean isSupported() { return true; 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 84abb44060..ed59a627c6 100644 --- a/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc +++ b/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc @@ -158,13 +158,13 @@ Alternatively, you can implement your own `Dialect`. [TIP] ==== -Dialects are resolved by javadoc:org.springframework.data.jdbc.repository.config.DialectResolver[] from a `JdbcOperations` instance, typically by inspecting `Connection.getMetaData()`. -+ You can let Spring auto-discover your javadoc:org.springframework.data.jdbc.core.dialect.JdbcDialect[] by registering a class that implements `org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider` through `META-INF/spring.factories`. +Dialects are resolved by javadoc:org.springframework.data.jdbc.core.dialect.DialectResolver[] from a `JdbcOperations` instance, typically by inspecting `Connection.getMetaData()`. ++ You can let Spring auto-discover your javadoc:org.springframework.data.jdbc.core.dialect.JdbcDialect[] by registering a class that implements `org.springframework.data.jdbc.core.dialect.DialectResolver$JdbcDialectProvider` through `META-INF/spring.factories`. `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`. . Register the provider by creating a `spring.factories` resource under `META-INF` and perform the registration by adding a line + -`org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=` +`org.springframework.data.jdbc.core.dialect.DialectResolver$JdbcDialectProvider`=` ====