Avoid conversion warnings for store specific simple types.
Dialects now can define a set of known simple types the driver can handle without further interaction. This is done to avoid warnings during converter registration for types known in one environment but not the other. Also move types around a bit, change visibility and make sure jdbc specific dialects inherit converters from their parents. Original pull request #981 See #935
This commit is contained in:
committed by
Jens Schauder
parent
6114d8e1fd
commit
35589af3d3
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
@@ -30,14 +31,14 @@ import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Christoph Strobl
|
||||
* @see CustomConversions
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder
|
||||
* @see JdbcSimpleTypes
|
||||
*/
|
||||
public class JdbcCustomConversions extends CustomConversions {
|
||||
|
||||
public static final List<Object> STORE_CONVERTERS = Arrays
|
||||
.asList(Jsr310TimestampBasedConverters.getConvertersToRegister().toArray());
|
||||
private static final Collection<Object> STORE_CONVERTERS = Collections.unmodifiableCollection(Jsr310TimestampBasedConverters.getConvertersToRegister());
|
||||
private static final StoreConversions STORE_CONVERSIONS = StoreConversions.of(JdbcSimpleTypes.HOLDER,
|
||||
STORE_CONVERTERS);
|
||||
|
||||
@@ -77,6 +78,16 @@ public class JdbcCustomConversions extends CustomConversions {
|
||||
super(converterConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a read only copy of default store converters.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
* @since 2.3
|
||||
*/
|
||||
public static Collection<Object> storeConverters() {
|
||||
return STORE_CONVERTERS;
|
||||
}
|
||||
|
||||
private static boolean isDateTimeApiConversion(ConvertiblePair cp) {
|
||||
|
||||
if (cp.getSourceType().equals(java.util.Date.class)) {
|
||||
|
||||
@@ -15,22 +15,29 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.dialect;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.relational.core.dialect.Db2Dialect;
|
||||
|
||||
/**
|
||||
* {@link Db2Dialect} that registers JDBC specific converters.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Christoph Strobl
|
||||
* @since 2.3
|
||||
*/
|
||||
public class JdbcDb2Dialect extends Db2Dialect {
|
||||
|
||||
public static JdbcDb2Dialect INSTANCE = new JdbcDb2Dialect();
|
||||
|
||||
protected JdbcDb2Dialect() {}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getConverters() {
|
||||
|
||||
@@ -40,4 +47,21 @@ public class JdbcDb2Dialect extends Db2Dialect {
|
||||
return converters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link WritingConverter} from {@link OffsetDateTime} to {@link Timestamp}. The conversion preserves the
|
||||
* {@link java.time.Instant} represented by {@link OffsetDateTime}
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.3
|
||||
*/
|
||||
@WritingConverter
|
||||
enum OffsetDateTimeToTimestampConverter implements Converter<OffsetDateTime, Timestamp> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Timestamp convert(OffsetDateTime source) {
|
||||
return Timestamp.from(source.toInstant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,36 +15,43 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.dialect;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.h2.api.TimestampWithTimeZone;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.relational.core.dialect.Db2Dialect;
|
||||
import org.springframework.data.relational.core.dialect.H2Dialect;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* {@link Db2Dialect} that registers JDBC specific converters.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Christoph Strobl
|
||||
* @since 2.3
|
||||
*/
|
||||
public class JdbcH2Dialect extends H2Dialect {
|
||||
|
||||
public static JdbcH2Dialect INSTANCE = new JdbcH2Dialect();
|
||||
|
||||
protected JdbcH2Dialect() {}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getConverters() {
|
||||
return Collections.singletonList(TimestampWithTimeZoneToOffsetDateTimeConverter.INSTANCE);
|
||||
|
||||
List<Object> converters = new ArrayList<>(super.getConverters());
|
||||
converters.add(TimestampWithTimeZoneToOffsetDateTimeConverter.INSTANCE);
|
||||
return converters;
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
enum TimestampWithTimeZoneToOffsetDateTimeConverter implements Converter<TimestampWithTimeZone, OffsetDateTime> {
|
||||
INSTANCE;
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public OffsetDateTime convert(TimestampWithTimeZone source) {
|
||||
@@ -67,8 +74,8 @@ public class JdbcH2Dialect extends H2Dialect {
|
||||
nanosLeft -= nanosInSeconds;
|
||||
ZoneOffset offset = ZoneOffset.ofTotalSeconds(source.getTimeZoneOffsetSeconds());
|
||||
|
||||
return OffsetDateTime.of(source.getYear(), source.getMonth(), source.getDay(), (int)hours, (int)minutes, (int)seconds, (int)nanosLeft, offset );
|
||||
|
||||
return OffsetDateTime.of(source.getYear(), source.getMonth(), source.getDay(), (int) hours, (int) minutes,
|
||||
(int) seconds, (int) nanosLeft, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
* {@link Db2Dialect} that registers JDBC specific converters.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Christoph Strobl
|
||||
* @since 2.3
|
||||
*/
|
||||
public class JdbcMySqlDialect extends MySqlDialect {
|
||||
@@ -39,6 +40,8 @@ public class JdbcMySqlDialect extends MySqlDialect {
|
||||
super(identifierProcessing);
|
||||
}
|
||||
|
||||
protected JdbcMySqlDialect() {}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getConverters() {
|
||||
|
||||
@@ -50,6 +53,7 @@ public class JdbcMySqlDialect extends MySqlDialect {
|
||||
|
||||
@WritingConverter
|
||||
enum OffsetDateTimeToTimestampJdbcValueConverter implements Converter<OffsetDateTime, JdbcValue> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,9 @@ package org.springframework.data.jdbc.core.dialect;
|
||||
import microsoft.sql.DateTimeOffset;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.data.relational.core.dialect.SqlServerDialect;
|
||||
* {@link SqlServerDialect} that registers JDBC specific converters.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Christoph Strobl
|
||||
* @since 2.3
|
||||
*/
|
||||
public class JdbcSqlServerDialect extends SqlServerDialect {
|
||||
@@ -37,11 +39,15 @@ public class JdbcSqlServerDialect extends SqlServerDialect {
|
||||
|
||||
@Override
|
||||
public Collection<Object> getConverters() {
|
||||
return Collections.singletonList(DateTimeOffsetToOffsetDateTimeConverter.INSTANCE);
|
||||
|
||||
List<Object> converters = new ArrayList<>(super.getConverters());
|
||||
converters.add(DateTimeOffsetToOffsetDateTimeConverter.INSTANCE);
|
||||
return converters;
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
enum DateTimeOffsetToOffsetDateTimeConverter implements Converter<DateTimeOffset, OffsetDateTime> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.relational.core.dialect.Db2Dialect;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
/**
|
||||
* {@link WritingConverter} from {@link OffsetDateTime} to {@link Timestamp}.
|
||||
* The conversion preserves the {@link java.time.Instant} represented by {@link OffsetDateTime}
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.3
|
||||
*/
|
||||
@WritingConverter
|
||||
enum OffsetDateTimeToTimestampConverter implements Converter<OffsetDateTime, Timestamp> {
|
||||
|
||||
INSTANCE;
|
||||
@Override
|
||||
public Timestamp convert(OffsetDateTime source) {
|
||||
return Timestamp.from(source.toInstant());
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.convert.CustomConversions.StoreConversions;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
|
||||
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
|
||||
@@ -41,9 +42,12 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
|
||||
import org.springframework.data.jdbc.core.convert.RelationResolver;
|
||||
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
|
||||
import org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.dialect.Db2Dialect;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
@@ -116,9 +120,11 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
|
||||
try {
|
||||
|
||||
Dialect dialect = applicationContext.getBean(Dialect.class);
|
||||
SimpleTypeHolder simpleTypeHolder = dialect.simpleTypes().isEmpty() ? JdbcSimpleTypes.HOLDER : new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER);
|
||||
|
||||
return new JdbcCustomConversions(
|
||||
CustomConversions.StoreConversions.of(JdbcSimpleTypes.HOLDER, storeConverters(dialect)), userConverters());
|
||||
CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), userConverters());
|
||||
|
||||
} catch (NoSuchBeanDefinitionException exception) {
|
||||
|
||||
LOG.warn("No dialect found. CustomConversions will be configured without dialect specific conversions.");
|
||||
@@ -135,7 +141,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
|
||||
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.addAll(dialect.getConverters());
|
||||
converters.addAll(JdbcCustomConversions.STORE_CONVERTERS);
|
||||
converters.addAll(JdbcCustomConversions.storeConverters());
|
||||
return converters;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests for {@link OffsetDateTimeToTimestampConverter}.
|
||||
* Tests for {@link JdbcDb2Dialect.OffsetDateTimeToTimestampConverter}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@@ -36,8 +36,8 @@ class OffsetDateTimeToTimestampConverterUnitTests {
|
||||
|
||||
OffsetDateTime offsetDateTime = OffsetDateTime.of(5, 5, 5, 5,5,5,123456789, ZoneOffset.ofHours(3));
|
||||
|
||||
Timestamp timestamp = OffsetDateTimeToTimestampConverter.INSTANCE.convert(offsetDateTime);
|
||||
Timestamp timestamp = JdbcDb2Dialect.OffsetDateTimeToTimestampConverter.INSTANCE.convert(offsetDateTime);
|
||||
|
||||
assertThat(timestamp.toInstant()).isEqualTo(offsetDateTime.toInstant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.jdbc.testing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -45,6 +44,7 @@ import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
|
||||
import org.springframework.data.jdbc.repository.config.DialectResolver;
|
||||
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
@@ -62,6 +62,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
* @author Mark Paluch
|
||||
* @author Fei Dong
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan // To pick up configuration classes (per activated profile)
|
||||
@@ -114,15 +115,19 @@ public class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
CustomConversions jdbcCustomConversions(Dialect dialect) {
|
||||
return new JdbcCustomConversions(CustomConversions.StoreConversions.of(JdbcSimpleTypes.HOLDER,
|
||||
storeConverters(dialect)), Collections.emptyList());
|
||||
|
||||
SimpleTypeHolder simpleTypeHolder = dialect.simpleTypes().isEmpty() ? JdbcSimpleTypes.HOLDER
|
||||
: new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER);
|
||||
|
||||
return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
private List<Object> storeConverters(Dialect dialect) {
|
||||
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.addAll(dialect.getConverters());
|
||||
converters.addAll(JdbcCustomConversions.STORE_CONVERTERS);
|
||||
converters.addAll(JdbcCustomConversions.storeConverters());
|
||||
return converters;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.relational.core.dialect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.data.relational.core.sql.render.SelectRenderContext;
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Christoph Strobl
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface Dialect {
|
||||
@@ -97,4 +99,14 @@ public interface Dialect {
|
||||
default Collection<Object> getConverters() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Set} of types considered store native types that can be handeled by the driver.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
* @since 2.3
|
||||
*/
|
||||
default Set<Class<?>> simpleTypes() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.relational.core.dialect;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
|
||||
@@ -26,6 +29,7 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Christph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
public class H2Dialect extends AbstractDialect {
|
||||
@@ -137,4 +141,21 @@ public class H2Dialect extends AbstractDialect {
|
||||
public IdentifierProcessing getIdentifierProcessing() {
|
||||
return IdentifierProcessing.create(Quoting.ANSI, LetterCasing.UPPER_CASE);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.relational.core.dialect.Dialect#simpleTypes()
|
||||
*/
|
||||
@Override
|
||||
public Set<Class<?>> simpleTypes() {
|
||||
|
||||
if (!ClassUtils.isPresent("org.h2.api.TimestampWithTimeZone", getClass().getClassLoader())) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
try {
|
||||
return Collections.singleton(ClassUtils.forName("org.h2.api.TimestampWithTimeZone", getClass().getClassLoader()));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user