Fix missing class issue with H2 version 2.0.202
With older versions H2 returned a proprietary instance of `TimestampWithTimeZone` from `ResultSet.getObject()`. We used to support the conversion of that to an `OffsetDateTime`. With the most recent versions `TimestampWithTimeZone` is no longer part of the H2 driver, and we only register the converter when we encounter older versions of H2. Closes #1114 See https://github.com/h2database/h2database/pull/1359
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
import org.h2.api.TimestampWithTimeZone;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
|
||||
/**
|
||||
* Converter converting from an H2 internal representation of a timestamp with time zone to an OffsetDateTime.
|
||||
*
|
||||
* Only required for H2 versions < 2.0
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.7
|
||||
*/
|
||||
@ReadingConverter
|
||||
public enum H2TimestampWithTimeZoneToOffsetDateTimeConverter
|
||||
implements Converter<TimestampWithTimeZone, OffsetDateTime> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public OffsetDateTime convert(TimestampWithTimeZone source) {
|
||||
|
||||
long nanosInSecond = 1_000_000_000;
|
||||
long nanosInMinute = nanosInSecond * 60;
|
||||
long nanosInHour = nanosInMinute * 60;
|
||||
|
||||
long hours = (source.getNanosSinceMidnight() / nanosInHour);
|
||||
|
||||
long nanosInHours = hours * nanosInHour;
|
||||
long nanosLeft = source.getNanosSinceMidnight() - nanosInHours;
|
||||
long minutes = nanosLeft / nanosInMinute;
|
||||
|
||||
long nanosInMinutes = minutes * nanosInMinute;
|
||||
nanosLeft -= nanosInMinutes;
|
||||
long seconds = nanosLeft / nanosInSecond;
|
||||
|
||||
long nanosInSeconds = seconds * nanosInSecond;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,10 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -43,39 +38,26 @@ public class JdbcH2Dialect extends H2Dialect {
|
||||
@Override
|
||||
public Collection<Object> getConverters() {
|
||||
|
||||
List<Object> converters = new ArrayList<>(super.getConverters());
|
||||
converters.add(TimestampWithTimeZoneToOffsetDateTimeConverter.INSTANCE);
|
||||
return converters;
|
||||
final Collection<Object> originalConverters = super.getConverters();
|
||||
|
||||
if (isH2belowVersion2()) {
|
||||
|
||||
List<Object> converters = new ArrayList<>(originalConverters);
|
||||
converters.add(H2TimestampWithTimeZoneToOffsetDateTimeConverter.INSTANCE);
|
||||
return converters;
|
||||
}
|
||||
|
||||
return originalConverters;
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
enum TimestampWithTimeZoneToOffsetDateTimeConverter implements Converter<TimestampWithTimeZone, OffsetDateTime> {
|
||||
static boolean isH2belowVersion2() {
|
||||
|
||||
INSTANCE;
|
||||
try {
|
||||
|
||||
@Override
|
||||
public OffsetDateTime convert(TimestampWithTimeZone source) {
|
||||
|
||||
long nanosInSecond = 1_000_000_000;
|
||||
long nanosInMinute = nanosInSecond * 60;
|
||||
long nanosInHour = nanosInMinute * 60;
|
||||
|
||||
long hours = (source.getNanosSinceMidnight() / nanosInHour);
|
||||
|
||||
long nanosInHours = hours * nanosInHour;
|
||||
long nanosLeft = source.getNanosSinceMidnight() - nanosInHours;
|
||||
long minutes = nanosLeft / nanosInMinute;
|
||||
|
||||
long nanosInMinutes = minutes * nanosInMinute;
|
||||
nanosLeft -= nanosInMinutes;
|
||||
long seconds = nanosLeft / nanosInSecond;
|
||||
|
||||
long nanosInSeconds = seconds * nanosInSecond;
|
||||
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);
|
||||
JdbcH2Dialect.class.getClassLoader().loadClass("org.h2.api.TimestampWithTimeZone");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class JdbcH2DialectTests {
|
||||
@Test
|
||||
void TimestampWithTimeZone2OffsetDateTimeConverterConvertsProperly() {
|
||||
|
||||
JdbcH2Dialect.TimestampWithTimeZoneToOffsetDateTimeConverter converter = JdbcH2Dialect.TimestampWithTimeZoneToOffsetDateTimeConverter.INSTANCE;
|
||||
H2TimestampWithTimeZoneToOffsetDateTimeConverter converter = H2TimestampWithTimeZoneToOffsetDateTimeConverter.INSTANCE;
|
||||
long dateValue = 123456789;
|
||||
long timeNanos = 987654321;
|
||||
int timeZoneOffsetSeconds = 4 * 60 * 60;
|
||||
|
||||
Reference in New Issue
Block a user