Support for timezones

- add TimestampWithTimeZoneDescriptor and use it in OffsetDateTimeJD
  and ZonedDateTimeJD
- add ZoneOffsetJavaDescriptor for ZoneOffset attributes
- clean up string rendering for temporal types using ISO formats;
  note that they do not need to implement objectToSQLString()
  since they cannot be discriminators

Note that at this time very few databases have meaningful support
for the ANSI-standard TIMESTAMP WITH TIME ZONE type. This limits
the usefulness of TimestampWithTimeZoneDescriptor for now.

Also add in some missing but needed type mappings for temporal types
This commit is contained in:
gavinking 2020-01-28 09:52:03 +01:00 committed by Steve Ebersole
parent 5a3838dfa6
commit 95930820af
24 changed files with 352 additions and 112 deletions

View File

@ -61,18 +61,6 @@ public Comparator<Date> getComparator() {
return getJavaTypeDescriptor().getComparator();
}
@Override
public String objectToSQLString(
Date value,
Dialect dialect) throws Exception {
final Timestamp ts = Timestamp.class.isInstance( value )
? ( Timestamp ) value
: new Timestamp( value.getTime() );
return StringType.INSTANCE.objectToSQLString(
ts.toString(), dialect
);
}
@Override
public Date fromStringValue(
String xml) throws HibernateException {

View File

@ -7,6 +7,8 @@
package org.hibernate.type;
import org.hibernate.dialect.Dialect;
/**
* Additional contract for a {@link Type} may be used for a discriminator.
*
@ -14,4 +16,15 @@
* @author Steve Ebersole
*/
public interface DiscriminatorType<T> extends IdentifierType<T>, LiteralType<T> {
/**
* Render the given discriminator value to a literal format
* for embedding in the generated SQL.
*
* @param value The value to convert
* @param dialect The SQL dialect
*
* @return The value's SQL literal representation
*/
@Override
String objectToSQLString(T value, Dialect dialect) throws Exception;
}

View File

@ -27,11 +27,6 @@ public DurationType() {
super( BigIntTypeDescriptor.INSTANCE, DurationJavaDescriptor.INSTANCE );
}
@Override
public String objectToSQLString(Duration value, Dialect dialect) throws Exception {
return String.valueOf( value.toNanos() );
}
@Override
public String getName() {
return Duration.class.getSimpleName();

View File

@ -43,11 +43,6 @@ public InstantType() {
super( TimestampTypeDescriptor.INSTANCE, InstantJavaDescriptor.INSTANCE );
}
@Override
public String objectToSQLString(Instant value, Dialect dialect) throws Exception {
return "{ts '" + FORMATTER.format( ZonedDateTime.ofInstant( value, ZoneId.of( "UTC" ) ) ) + "'}";
}
@Override
public Instant seed(SharedSessionContractImplementor session) {
return Instant.now();

View File

@ -5,6 +5,7 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import org.hibernate.AssertionFailure;
import org.hibernate.dialect.Dialect;
/**
@ -29,6 +30,8 @@ public interface LiteralType<T> {
*
* @throws Exception Indicates an issue converting the value to literal string.
*/
public String objectToSQLString(T value, Dialect dialect) throws Exception;
default String objectToSQLString(T value, Dialect dialect) throws Exception {
throw new AssertionFailure("not a discriminator type");
}
}

View File

@ -9,7 +9,6 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Locale;
import javax.persistence.TemporalType;
@ -35,8 +34,6 @@ public class LocalDateTimeType
*/
public static final LocalDateTimeType INSTANCE = new LocalDateTimeType();
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss.S", Locale.ENGLISH );
public LocalDateTimeType() {
super( TimestampTypeDescriptor.INSTANCE, LocalDateTimeJavaDescriptor.INSTANCE );
}
@ -51,11 +48,6 @@ protected boolean registerUnderJavaType() {
return true;
}
@Override
public String objectToSQLString(LocalDateTime value, Dialect dialect) throws Exception {
return "{ts '" + FORMATTER.format( value ) + "'}";
}
@Override
public LocalDateTime seed(SharedSessionContractImplementor session) {
return LocalDateTime.now();

View File

@ -8,7 +8,6 @@
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import javax.persistence.TemporalType;
import org.hibernate.QueryException;
@ -30,8 +29,6 @@ public class LocalDateType
*/
public static final LocalDateType INSTANCE = new LocalDateType();
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd", Locale.ENGLISH );
public LocalDateType() {
super( DateTypeDescriptor.INSTANCE, LocalDateJavaDescriptor.INSTANCE );
}
@ -46,11 +43,6 @@ protected boolean registerUnderJavaType() {
return true;
}
@Override
public String objectToSQLString(LocalDate value, Dialect dialect) throws Exception {
return "{d '" + FORMATTER.format( value ) + "'}";
}
@Override
public AllowableTemporalParameterType resolveTemporalPrecision(
TemporalType temporalPrecision,

View File

@ -8,7 +8,6 @@
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import javax.persistence.TemporalType;
@ -31,8 +30,6 @@ public class LocalTimeType
*/
public static final LocalTimeType INSTANCE = new LocalTimeType();
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "HH:mm:ss", Locale.ENGLISH );
public LocalTimeType() {
super( TimeTypeDescriptor.INSTANCE, LocalTimeJavaDescriptor.INSTANCE );
}
@ -47,11 +44,6 @@ protected boolean registerUnderJavaType() {
return true;
}
@Override
public String objectToSQLString(LocalTime value, Dialect dialect) throws Exception {
return "{t '" + FORMATTER.format( value ) + "'}";
}
@Override
public AllowableTemporalParameterType resolveTemporalPrecision(
TemporalType temporalPrecision,

View File

@ -7,18 +7,15 @@
package org.hibernate.type;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Locale;
import javax.persistence.TemporalType;
import org.hibernate.QueryException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
import org.hibernate.type.descriptor.java.OffsetDateTimeJavaDescriptor;
import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimestampWithTimeZoneDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -33,15 +30,8 @@ public class OffsetDateTimeType
*/
public static final OffsetDateTimeType INSTANCE = new OffsetDateTimeType();
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss.S xxxxx", Locale.ENGLISH );
public OffsetDateTimeType() {
super( TimestampTypeDescriptor.INSTANCE, OffsetDateTimeJavaDescriptor.INSTANCE );
}
@Override
public String objectToSQLString(OffsetDateTime value, Dialect dialect) throws Exception {
return "{ts '" + FORMATTER.format( value ) + "'}";
super( TimestampWithTimeZoneDescriptor.INSTANCE, OffsetDateTimeJavaDescriptor.INSTANCE );
}
@Override

View File

@ -8,7 +8,6 @@
import java.time.OffsetTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import javax.persistence.TemporalType;
@ -31,17 +30,10 @@ public class OffsetTimeType
*/
public static final OffsetTimeType INSTANCE = new OffsetTimeType();
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "HH:mm:ss.S xxxxx", Locale.ENGLISH );
public OffsetTimeType() {
super( TimeTypeDescriptor.INSTANCE, OffsetTimeJavaDescriptor.INSTANCE );
}
@Override
public String objectToSQLString(OffsetTime value, Dialect dialect) throws Exception {
return "{t '" + FORMATTER.format( value ) + "'}";
}
@Override
public String getName() {
return OffsetTime.class.getSimpleName();

View File

@ -19,6 +19,7 @@
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Currency;
@ -463,6 +464,13 @@ private StandardBasicTypes() {
*/
public static final CurrencyType CURRENCY = CurrencyType.INSTANCE;
/**
* The standard Hibernate type for mapping {@link java.time.ZoneOffset} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}.
*
* @see ZoneOffsetType
*/
public static final ZoneOffsetType ZONE_OFFSET = ZoneOffsetType.INSTANCE;
/**
* The standard Hibernate type for mapping {@link java.util.TimeZone} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}.
*
@ -927,6 +935,13 @@ public static void prime(TypeConfiguration typeConfiguration) {
"timezone", TimeZone.class.getName()
);
handle(
ZONE_OFFSET,
"org.hibernate.type.ZoneOffsetType",
basicTypeRegistry,
ZoneOffset.class.getSimpleName(), ZoneOffset.class.getName()
);
handle(
URL,
"org.hibernate.type.UrlType",

View File

@ -50,14 +50,6 @@ public String[] getRegistrationKeys() {
// return true;
// }
public String objectToSQLString(Date value, Dialect dialect) throws Exception {
Time jdbcTime = Time.class.isInstance( value )
? ( Time ) value
: new Time( value.getTime() );
// TODO : use JDBC time literal escape syntax? -> {t 'time-string'} in hh:mm:ss format
return StringType.INSTANCE.objectToSQLString( jdbcTime.toString(), dialect );
}
@Override
public AllowableTemporalParameterType resolveTemporalPrecision(
TemporalType temporalPrecision,

View File

@ -62,15 +62,6 @@ public Comparator<Date> getComparator() {
return getJavaTypeDescriptor().getComparator();
}
@Override
public String objectToSQLString(Date value, Dialect dialect) throws Exception {
final Timestamp ts = Timestamp.class.isInstance( value )
? ( Timestamp ) value
: new Timestamp( value.getTime() );
// TODO : use JDBC date literal escape syntax? -> {d 'date-string'} in yyyy-mm-dd hh:mm:ss[.f...] format
return StringType.INSTANCE.objectToSQLString( ts.toString(), dialect );
}
@Override
public Date fromStringValue(String xml) throws HibernateException {
return fromString( xml );

View File

@ -0,0 +1,44 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.ZoneOffsetJavaDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
import java.time.ZoneOffset;
/**
* A type mapping {@link java.sql.Types#VARCHAR VARCHAR} and {@link ZoneOffset}
*
* @author Gavin King
* @author Steve Ebersole
*/
public class ZoneOffsetType
extends AbstractSingleColumnStandardBasicType<ZoneOffset>
implements LiteralType<ZoneOffset> {
public static final ZoneOffsetType INSTANCE = new ZoneOffsetType();
public ZoneOffsetType() {
super( VarcharTypeDescriptor.INSTANCE, ZoneOffsetJavaDescriptor.INSTANCE );
}
public String getName() {
return ZoneOffset.class.getSimpleName();
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
public String objectToSQLString(ZoneOffset value, Dialect dialect) throws Exception {
return StringType.INSTANCE.objectToSQLString( value.getId(), dialect );
}
}

View File

@ -20,6 +20,7 @@
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
import org.hibernate.type.descriptor.java.ZonedDateTimeJavaDescriptor;
import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimestampWithTimeZoneDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -34,15 +35,8 @@ public class ZonedDateTimeType
*/
public static final ZonedDateTimeType INSTANCE = new ZonedDateTimeType();
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss.S VV", Locale.ENGLISH );
public ZonedDateTimeType() {
super( TimestampTypeDescriptor.INSTANCE, ZonedDateTimeJavaDescriptor.INSTANCE );
}
@Override
public String objectToSQLString(ZonedDateTime value, Dialect dialect) throws Exception {
return "{ts '" + FORMATTER.format( value ) + "'}";
super( TimestampWithTimeZoneDescriptor.INSTANCE, ZonedDateTimeJavaDescriptor.INSTANCE );
}
@Override

View File

@ -12,11 +12,11 @@
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.hibernate.type.LocalDateType;
import org.hibernate.type.descriptor.WrapperOptions;
/**
@ -37,12 +37,12 @@ public LocalDateJavaDescriptor() {
@Override
public String toString(LocalDate value) {
return LocalDateType.FORMATTER.format( value );
return DateTimeFormatter.ISO_LOCAL_DATE.format( value );
}
@Override
public LocalDate fromString(String string) {
return LocalDate.from( LocalDateType.FORMATTER.parse( string ) );
return LocalDate.from( DateTimeFormatter.ISO_LOCAL_DATE.parse( string ) );
}
@Override

View File

@ -10,12 +10,12 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.LocalDateTimeType;
import org.hibernate.type.descriptor.WrapperOptions;
/**
@ -36,12 +36,12 @@ public LocalDateTimeJavaDescriptor() {
@Override
public String toString(LocalDateTime value) {
return LocalDateTimeType.FORMATTER.format( value );
return DateTimeFormatter.ISO_DATE_TIME.format( value );
}
@Override
public LocalDateTime fromString(String string) {
return LocalDateTime.from( LocalDateTimeType.FORMATTER.parse( string ) );
return LocalDateTime.from( DateTimeFormatter.ISO_DATE_TIME.parse( string ) );
}
@Override

View File

@ -14,12 +14,12 @@
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.LocalTimeType;
import org.hibernate.type.descriptor.WrapperOptions;
/**
@ -40,12 +40,12 @@ public LocalTimeJavaDescriptor() {
@Override
public String toString(LocalTime value) {
return LocalTimeType.FORMATTER.format( value );
return DateTimeFormatter.ISO_LOCAL_TIME.format( value );
}
@Override
public LocalTime fromString(String string) {
return LocalTime.from( LocalTimeType.FORMATTER.parse( string ) );
return LocalTime.from( DateTimeFormatter.ISO_LOCAL_TIME.parse( string ) );
}
@Override

View File

@ -10,16 +10,17 @@
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.OffsetDateTimeType;
import org.hibernate.type.descriptor.WrapperOptions;
/**
* Java type descriptor for the LocalDateTime type.
* Java type descriptor for the {@link OffsetDateTime} type.
*
* @author Steve Ebersole
*/
@ -36,12 +37,12 @@ public OffsetDateTimeJavaDescriptor() {
@Override
public String toString(OffsetDateTime value) {
return OffsetDateTimeType.FORMATTER.format( value );
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format( value );
}
@Override
public OffsetDateTime fromString(String string) {
return OffsetDateTime.from( OffsetDateTimeType.FORMATTER.parse( string ) );
return OffsetDateTime.from( DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse( string ) );
}
@Override
@ -55,6 +56,10 @@ public <X> X unwrap(OffsetDateTime offsetDateTime, Class<X> type, WrapperOptions
return (X) offsetDateTime;
}
if ( ZonedDateTime.class.isAssignableFrom( type ) ) {
return (X) offsetDateTime.toZonedDateTime();
}
if ( Calendar.class.isAssignableFrom( type ) ) {
return (X) GregorianCalendar.from( offsetDateTime.toZonedDateTime() );
}
@ -109,6 +114,11 @@ public <X> OffsetDateTime wrap(X value, WrapperOptions options) {
return (OffsetDateTime) value;
}
if ( ZonedDateTime.class.isInstance( value ) ) {
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
return OffsetDateTime.of( zonedDateTime.toLocalDateTime(), zonedDateTime.getOffset() );
}
if ( Timestamp.class.isInstance( value ) ) {
final Timestamp ts = (Timestamp) value;
/*

View File

@ -14,12 +14,12 @@
import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.OffsetTimeType;
import org.hibernate.type.descriptor.WrapperOptions;
/**
@ -40,12 +40,12 @@ public OffsetTimeJavaDescriptor() {
@Override
public String toString(OffsetTime value) {
return OffsetTimeType.FORMATTER.format( value );
return DateTimeFormatter.ISO_OFFSET_TIME.format( value );
}
@Override
public OffsetTime fromString(String string) {
return OffsetTime.from( OffsetTimeType.FORMATTER.parse( string ) );
return OffsetTime.from( DateTimeFormatter.ISO_OFFSET_TIME.parse( string ) );
}
@Override

View File

@ -0,0 +1,82 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type.descriptor.java;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
import java.time.ZoneOffset;
import java.util.Comparator;
/**
* Descriptor for {@link ZoneOffset} handling.
*
* @author Gavin King
*/
public class ZoneOffsetJavaDescriptor extends AbstractTypeDescriptor<ZoneOffset> {
public static final ZoneOffsetJavaDescriptor INSTANCE = new ZoneOffsetJavaDescriptor();
public static class ZoneOffsetComparator implements Comparator<ZoneOffset> {
public static final ZoneOffsetComparator INSTANCE = new ZoneOffsetComparator();
public int compare(ZoneOffset o1, ZoneOffset o2) {
return o1.getId().compareTo( o2.getId() );
}
}
public ZoneOffsetJavaDescriptor() {
super( ZoneOffset.class );
}
public String toString(ZoneOffset value) {
return value.getId();
}
public ZoneOffset fromString(String string) {
return ZoneOffset.of( string );
}
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
return StringTypeDescriptor.INSTANCE.getJdbcRecommendedSqlType( context );
}
@Override
public Comparator<ZoneOffset> getComparator() {
return ZoneOffsetComparator.INSTANCE;
}
@Override
@SuppressWarnings({ "unchecked" })
public <X> X unwrap(ZoneOffset value, Class<X> type, WrapperOptions wrapperOptions) {
if ( value == null ) {
return null;
}
if ( String.class.isAssignableFrom( type ) ) {
return (X) toString( value );
}
throw unknownUnwrap( type );
}
@Override
public <X> ZoneOffset wrap(X value, WrapperOptions wrapperOptions) {
if ( value == null ) {
return null;
}
if ( String.class.isInstance( value ) ) {
return fromString( (String) value );
}
throw unknownWrap( value.getClass() );
}
@Override
public long getDefaultSqlLength(Dialect dialect) {
return 6;
}
}

View File

@ -8,18 +8,19 @@
import java.sql.Timestamp;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.ZonedDateTimeType;
import org.hibernate.type.descriptor.WrapperOptions;
/**
* Java type descriptor for the LocalDateTime type.
* Java type descriptor for the {@link ZonedDateTime} type.
*
* @author Steve Ebersole
*/
@ -36,12 +37,12 @@ public ZonedDateTimeJavaDescriptor() {
@Override
public String toString(ZonedDateTime value) {
return ZonedDateTimeType.FORMATTER.format( value );
return DateTimeFormatter.ISO_ZONED_DATE_TIME.format( value );
}
@Override
public ZonedDateTime fromString(String string) {
return ZonedDateTime.from( ZonedDateTimeType.FORMATTER.parse( string ) );
return ZonedDateTime.from( DateTimeFormatter.ISO_ZONED_DATE_TIME.parse( string ) );
}
@Override
@ -55,6 +56,10 @@ public <X> X unwrap(ZonedDateTime zonedDateTime, Class<X> type, WrapperOptions o
return (X) zonedDateTime;
}
if ( OffsetDateTime.class.isAssignableFrom( type ) ) {
return (X) OffsetDateTime.of( zonedDateTime.toLocalDateTime(), zonedDateTime.getOffset() );
}
if ( Calendar.class.isAssignableFrom( type ) ) {
return (X) GregorianCalendar.from( zonedDateTime );
}
@ -109,6 +114,11 @@ public <X> ZonedDateTime wrap(X value, WrapperOptions options) {
return (ZonedDateTime) value;
}
if ( OffsetDateTime.class.isInstance( value ) ) {
OffsetDateTime offsetDateTime = (OffsetDateTime) value;
return offsetDateTime.toZonedDateTime();
}
if ( java.sql.Timestamp.class.isInstance( value ) ) {
final Timestamp ts = (Timestamp) value;
/*

View File

@ -18,6 +18,11 @@
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.concurrent.ConcurrentHashMap;
@ -112,6 +117,11 @@ private static ConcurrentHashMap<Class, Integer> buildJavaClassToJdbcTypeCodeMap
workMap.put( java.sql.Date.class, Types.DATE );
workMap.put( Time.class, Types.TIME );
workMap.put( Timestamp.class, Types.TIMESTAMP );
workMap.put( LocalTime.class, Types.TIME );
workMap.put( LocalDate.class, Types.DATE );
workMap.put( LocalDateTime.class, Types.TIMESTAMP );
workMap.put( OffsetDateTime.class, Types.TIMESTAMP_WITH_TIMEZONE );
workMap.put( ZonedDateTime.class, Types.TIMESTAMP_WITH_TIMEZONE );
workMap.put( Blob.class, Types.BLOB );
workMap.put( Clob.class, Types.CLOB );
workMap.put( Array.class, Types.ARRAY );

View File

@ -0,0 +1,140 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type.descriptor.sql;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterTemporal;
import org.hibernate.type.spi.TypeConfiguration;
import javax.persistence.TemporalType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.OffsetDateTime;
/**
* Descriptor for {@link Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE} handling.
*
* @author Gavin King
*/
public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
public static final TimestampWithTimeZoneDescriptor INSTANCE = new TimestampWithTimeZoneDescriptor();
public TimestampWithTimeZoneDescriptor() {
}
@Override
public int getSqlType() {
return Types.TIMESTAMP_WITH_TIMEZONE;
}
@Override
public boolean canBeRemapped() {
return true;
}
@Override
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( OffsetDateTime.class );
}
@Override
@SuppressWarnings("unchecked")
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
return new JdbcLiteralFormatterTemporal( javaTypeDescriptor, TemporalType.TIMESTAMP );
}
@Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBind(
PreparedStatement st,
X value,
int index,
WrapperOptions wrapperOptions) throws SQLException {
try {
final OffsetDateTime dateTime = javaTypeDescriptor.unwrap( value, OffsetDateTime.class, wrapperOptions.getSession() );
// supposed to be supported in JDBC 4.2
st.setObject( index, dateTime, Types.TIMESTAMP_WITH_TIMEZONE );
}
catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp
final Timestamp timestamp = javaTypeDescriptor.unwrap( value, Timestamp.class, wrapperOptions.getSession() );
st.setTimestamp( index, timestamp );
}
}
@Override
protected void doBind(
CallableStatement st,
X value,
String name,
WrapperOptions wrapperOptions)
throws SQLException {
try {
final OffsetDateTime dateTime = javaTypeDescriptor.unwrap( value, OffsetDateTime.class, wrapperOptions.getSession() );
// supposed to be supported in JDBC 4.2
st.setObject( name, dateTime, Types.TIMESTAMP_WITH_TIMEZONE );
}
catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp
final Timestamp timestamp = javaTypeDescriptor.unwrap( value, Timestamp.class, wrapperOptions.getSession() );
st.setTimestamp( name, timestamp );
}
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException {
try {
// supposed to be supported in JDBC 4.2
return javaTypeDescriptor.wrap( rs.getObject( position, OffsetDateTime.class ), wrapperOptions.getSession() );
}
catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp
return javaTypeDescriptor.wrap( rs.getTimestamp( position ), wrapperOptions.getSession() );
}
}
@Override
protected X doExtract(CallableStatement statement, int position, WrapperOptions wrapperOptions) throws SQLException {
try {
// supposed to be supported in JDBC 4.2
return javaTypeDescriptor.wrap( statement.getObject( position, OffsetDateTime.class ), wrapperOptions.getSession() );
}
catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp
return javaTypeDescriptor.wrap( statement.getTimestamp( position ), wrapperOptions.getSession() );
}
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions wrapperOptions) throws SQLException {
try {
// supposed to be supported in JDBC 4.2
return javaTypeDescriptor.wrap( statement.getObject( name, OffsetDateTime.class ), wrapperOptions.getSession() );
}
catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp
return javaTypeDescriptor.wrap( statement.getTimestamp( name ), wrapperOptions.getSession() );
}
}
};
}
}