diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcCustomConversions.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcCustomConversions.java index 81befa9ab..aff510d59 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcCustomConversions.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/JdbcCustomConversions.java @@ -22,6 +22,10 @@ import java.util.List; import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair; import org.springframework.data.convert.CustomConversions; import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; +import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.lang.Contract; +import org.springframework.util.Assert; /** * Value object to capture custom conversion. {@link JdbcCustomConversions} also act as factory for 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 bc45ad3dd..438e06630 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 @@ -22,6 +22,7 @@ import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; @@ -33,12 +34,20 @@ import org.springframework.data.relational.core.dialect.SqlServerDialect; * @author Jens Schauder * @author Christoph Strobl * @author Mikhail Polivakha + * @author Mark Paluch * @since 2.3 */ public class JdbcSqlServerDialect extends SqlServerDialect implements JdbcDialect { public static final JdbcSqlServerDialect INSTANCE = new JdbcSqlServerDialect(); + private static final Set> SIMPLE_TYPES = Set.of(DateTimeOffset.class); + + @Override + public Set> simpleTypes() { + return SIMPLE_TYPES; + } + @Override public Collection getConverters() { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialectUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialectUnitTests.java index a0d899126..6c37ff79f 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialectUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcPostgresDialectUnitTests.java @@ -17,7 +17,12 @@ package org.springframework.data.jdbc.core.dialect; import static org.assertj.core.api.Assertions.*; +import java.util.ArrayList; +import java.util.List; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.postgresql.geometric.PGbox; import org.postgresql.geometric.PGcircle; import org.postgresql.geometric.PGlseg; @@ -26,28 +31,58 @@ import org.postgresql.geometric.PGpoint; import org.postgresql.geometric.PGpolygon; import org.postgresql.util.PGobject; +import org.springframework.data.convert.CustomConversions; +import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; +import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; +import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.relational.core.dialect.Dialect; + /** * Unit tests for {@link JdbcPostgresDialect}. * * @author Jens Schauder + * @author Mark Paluch */ -public class JdbcPostgresDialectUnitTests { +class JdbcPostgresDialectUnitTests { @Test // GH-1065 void pgobjectIsConsideredSimple() { assertThat(JdbcPostgresDialect.INSTANCE.simpleTypes()).contains(PGobject.class); } - @Test // GH-1065 - void geometricalTypesAreConsideredSimple() { + @ParameterizedTest // GH-1065, GH-2147 + @MethodSource("simpleTypes") + void simpleTypesAreConsideredSimple(Class type) { + + JdbcCustomConversions conversions = createCustomConversions(JdbcPostgresDialect.INSTANCE); + + assertThat(conversions.isSimpleType(type)).isTrue(); + assertThat(conversions.getSimpleTypeHolder().isSimpleType(type)).isTrue(); + } - assertThat(JdbcPostgresDialect.INSTANCE.simpleTypes()).contains( // - PGpoint.class, // + static List> simpleTypes() { + return List.of(PGpoint.class, // PGbox.class, // PGcircle.class, // org.postgresql.geometric.PGline.class, // PGpath.class, // PGpolygon.class, // - PGlseg.class); + PGlseg.class, // + PGobject.class); + } + + private static JdbcCustomConversions createCustomConversions(JdbcDialect dialect) { + + SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); + return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), + List.of()); + } + + private static List storeConverters(Dialect dialect) { + + List converters = new ArrayList<>(); + converters.addAll(dialect.getConverters()); + converters.addAll(JdbcCustomConversions.storeConverters()); + return converters; } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialectTest.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialectTest.java index 3a67ff109..ad3326751 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialectTest.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/dialect/JdbcSqlServerDialectTest.java @@ -17,26 +17,58 @@ package org.springframework.data.jdbc.core.dialect; import static org.assertj.core.api.Assertions.*; +import microsoft.sql.DateTimeOffset; + import java.time.Instant; +import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; +import org.springframework.data.convert.CustomConversions; import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; +import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; +import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.relational.core.dialect.Dialect; /** * Tests for {@link JdbcSqlServerDialect} * * @author Mikhail Polivakha + * @author Mark Paluch */ class JdbcSqlServerDialectTest { @Test // GH-1873 void testCustomConversions() { - JdbcCustomConversions conversions = JdbcCustomConversions.of(JdbcSqlServerDialect.INSTANCE, List.of()); + JdbcCustomConversions conversions = createCustomConversions(JdbcSqlServerDialect.INSTANCE); - assertThat(conversions.hasCustomReadTarget(microsoft.sql.DateTimeOffset.class, Instant.class)) + assertThat(conversions.hasCustomReadTarget(DateTimeOffset.class, Instant.class)) .isTrue(); } + + @Test // GH-2147 + void shouldReportSimpleTypes() { + + JdbcCustomConversions conversions = createCustomConversions(JdbcSqlServerDialect.INSTANCE); + + assertThat(conversions.isSimpleType(DateTimeOffset.class)).isTrue(); + assertThat(conversions.getSimpleTypeHolder().isSimpleType(DateTimeOffset.class)).isTrue(); + } + + private static JdbcCustomConversions createCustomConversions(JdbcDialect dialect) { + + SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); + return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), + List.of()); + } + + private static List storeConverters(Dialect dialect) { + + List converters = new ArrayList<>(); + converters.addAll(dialect.getConverters()); + converters.addAll(JdbcCustomConversions.storeConverters()); + return converters; + } } diff --git a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversions.java b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversions.java index 0e0c1f9f7..5503cddab 100644 --- a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversions.java +++ b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2018-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.r2dbc.convert; import java.util.ArrayList; diff --git a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcDialect.java b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcDialect.java index a1c47e6d2..b6cf1b95f 100644 --- a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcDialect.java +++ b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/R2dbcDialect.java @@ -49,7 +49,7 @@ public interface R2dbcDialect extends Dialect { Set> simpleTypes = new HashSet<>(getSimpleTypes()); simpleTypes.addAll(R2dbcSimpleTypeHolder.R2DBC_SIMPLE_TYPES); - return new SimpleTypeHolder(simpleTypes, true); + return new SimpleTypeHolder(simpleTypes, R2dbcSimpleTypeHolder.HOLDER); } /** diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversionsUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversionsUnitTests.java new file mode 100644 index 000000000..a0735c6a7 --- /dev/null +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversionsUnitTests.java @@ -0,0 +1,40 @@ +/* + * 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.r2dbc.convert; + +import static org.assertj.core.api.Assertions.*; + +import io.r2dbc.spi.Blob; + +import org.junit.jupiter.api.Test; + +import org.springframework.data.r2dbc.dialect.H2Dialect; + +/** + * Unit tests for {@link R2dbcCustomConversions}. + * + * @author Mark Paluch + */ +class R2dbcCustomConversionsUnitTests { + + @Test // GH-2147 + void shouldReportR2dbcSimpleTypes() { + + R2dbcCustomConversions conversions = R2dbcCustomConversions.of(H2Dialect.INSTANCE); + + assertThat(conversions.isSimpleType(Blob.class)).isTrue(); + } +} diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/dialect/PostgresDialectUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/dialect/PostgresDialectUnitTests.java index 3ce59bf8d..d6cf1a316 100644 --- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/dialect/PostgresDialectUnitTests.java +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/dialect/PostgresDialectUnitTests.java @@ -18,6 +18,8 @@ package org.springframework.data.r2dbc.dialect; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.SoftAssertions.*; +import io.r2dbc.postgresql.codec.Box; + import java.util.List; import org.junit.jupiter.api.Test; @@ -55,6 +57,7 @@ class PostgresDialectUnitTests { it.assertThat(holder.isSimpleType(String.class)).isTrue(); it.assertThat(holder.isSimpleType(int.class)).isTrue(); it.assertThat(holder.isSimpleType(Integer.class)).isTrue(); + it.assertThat(holder.isSimpleType(Box.class)).isTrue(); }); }