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 class TimestampEpochType
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 @@ package org.hibernate.type;
* @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 class 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 class 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 @@ package org.hibernate.type;
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 @@ public class LocalDateTimeType
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 @@ package org.hibernate.type;
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 @@ public class LocalDateType
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 @@ package org.hibernate.type;
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 @@ public class LocalTimeType
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 @@ package org.hibernate.type;
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.LocalDateTime;
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 @@ public final class 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 final class StandardBasicTypes {
"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 class TimeType
// 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 class TimestampType
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.internal.util.ZonedDateTimeComparator;
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.LocalDate;
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 class LocalDateJavaDescriptor extends AbstractTypeDescriptor<LocalDate> {
@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.sql.Timestamp;
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 class LocalDateTimeJavaDescriptor extends AbstractTypeDescriptor<LocalDat
@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.LocalDateTime;
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 class LocalTimeJavaDescriptor extends AbstractTypeDescriptor<LocalTime> {
@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.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.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 class OffsetDateTimeJavaDescriptor extends AbstractTypeDescriptor<OffsetD
@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 class OffsetDateTimeJavaDescriptor extends AbstractTypeDescriptor<OffsetD
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 class OffsetDateTimeJavaDescriptor extends AbstractTypeDescriptor<OffsetD
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.OffsetDateTime;
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 class OffsetTimeJavaDescriptor extends AbstractTypeDescriptor<OffsetTime>
@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 @@ package org.hibernate.type.descriptor.java;
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 class ZonedDateTimeJavaDescriptor extends AbstractTypeDescriptor<ZonedDat
@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 class ZonedDateTimeJavaDescriptor extends AbstractTypeDescriptor<ZonedDat
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 class ZonedDateTimeJavaDescriptor extends AbstractTypeDescriptor<ZonedDat
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.Struct;
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 @@ public class JdbcTypeJavaClassMappings {
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() );
}
}
};
}
}