HHH-14919 - Improve handling for java.sql.Date, Time and Timestamp
This commit is contained in:
parent
9c9a326ae6
commit
599b0ba39f
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.userguide.mapping.basic;
|
||||
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
@ -45,7 +47,7 @@ public class DatePrecisionTests {
|
|||
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
|
||||
final TemporalJavaTypeDescriptor jtd = (TemporalJavaTypeDescriptor) jdbcMapping.getJavaTypeDescriptor();
|
||||
assertThat( jtd, is( attribute.getJavaTypeDescriptor() ) );
|
||||
assertThat( jtd.getJavaTypeClass(), equalTo( Date.class ) );
|
||||
assertThat( jtd.getJavaTypeClass(), equalTo( Timestamp.class ) );
|
||||
assertThat( jtd.getPrecision(), equalTo( TemporalType.TIMESTAMP ) );
|
||||
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIMESTAMP ) );
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ public class DatePrecisionTests {
|
|||
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
|
||||
final TemporalJavaTypeDescriptor jtd = (TemporalJavaTypeDescriptor) jdbcMapping.getJavaTypeDescriptor();
|
||||
assertThat( jtd, is( attribute.getJavaTypeDescriptor() ) );
|
||||
assertThat( jtd.getJavaTypeClass(), equalTo( Date.class ) );
|
||||
assertThat( jtd.getJavaTypeClass(), equalTo( java.sql.Date.class ) );
|
||||
assertThat( jtd.getPrecision(), equalTo( TemporalType.DATE ) );
|
||||
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.DATE ) );
|
||||
}
|
||||
|
@ -65,7 +67,7 @@ public class DatePrecisionTests {
|
|||
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
|
||||
final TemporalJavaTypeDescriptor jtd = (TemporalJavaTypeDescriptor) jdbcMapping.getJavaTypeDescriptor();
|
||||
assertThat( jtd, is( attribute.getJavaTypeDescriptor() ) );
|
||||
assertThat( jtd.getJavaTypeClass(), equalTo( Date.class ) );
|
||||
assertThat( jtd.getJavaTypeClass(), equalTo( Time.class ) );
|
||||
assertThat( jtd.getPrecision(), equalTo( TemporalType.TIME ) );
|
||||
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIME ) );
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.Filter;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.FilterDefinition;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
|
@ -74,12 +75,11 @@ public class FilterImpl implements Filter, Serializable {
|
|||
*/
|
||||
public Filter setParameter(String name, Object value) throws IllegalArgumentException {
|
||||
// Make sure this is a defined parameter and check the incoming value type
|
||||
// TODO: what should be the actual exception type here?
|
||||
Type type = definition.getParameterType( name );
|
||||
BasicType<?> type = (BasicType<?>) definition.getParameterType( name );
|
||||
if ( type == null ) {
|
||||
throw new IllegalArgumentException( "Undefined filter parameter [" + name + "]" );
|
||||
}
|
||||
if ( value != null && !type.getReturnedClass().isAssignableFrom( value.getClass() ) ) {
|
||||
if ( value != null && !type.getJavaTypeDescriptor().isInstance( value ) ) {
|
||||
throw new IllegalArgumentException( "Incorrect type for parameter [" + name + "]" );
|
||||
}
|
||||
parameters.put( name, value );
|
||||
|
|
|
@ -180,13 +180,11 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
this.bindType = clarifiedType;
|
||||
}
|
||||
|
||||
if ( ! getTypeConfiguration().getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
|
||||
if ( bindType != null ) {
|
||||
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||
}
|
||||
else if ( queryParameter.getHibernateType() != null ) {
|
||||
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||
}
|
||||
if ( bindType != null ) {
|
||||
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||
}
|
||||
else if ( queryParameter.getHibernateType() != null ) {
|
||||
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||
}
|
||||
|
||||
if ( isBindingValidationRequired ) {
|
||||
|
|
|
@ -17,7 +17,7 @@ public class JdbcParameterBindingImpl implements JdbcParameterBinding {
|
|||
private final Object bindValue;
|
||||
|
||||
public JdbcParameterBindingImpl(JdbcMapping jdbcMapping, Object bindValue) {
|
||||
assert bindValue == null || jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass().isInstance( bindValue );
|
||||
assert bindValue == null || jdbcMapping.getJavaTypeDescriptor().isInstance( bindValue );
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
this.bindValue = bindValue;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public abstract class AbstractClassJavaTypeDescriptor<T> implements BasicJavaTyp
|
|||
* @see #AbstractClassJavaTypeDescriptor(Class, MutabilityPlan)
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected AbstractClassJavaTypeDescriptor(Class<T> type) {
|
||||
protected AbstractClassJavaTypeDescriptor(Class<? extends T> type) {
|
||||
this( type, (MutabilityPlan<T>) ImmutableMutabilityPlan.INSTANCE );
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ public abstract class AbstractClassJavaTypeDescriptor<T> implements BasicJavaTyp
|
|||
* @param mutabilityPlan The plan for handling mutability aspects of the java type.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected AbstractClassJavaTypeDescriptor(Class<T> type, MutabilityPlan<T> mutabilityPlan) {
|
||||
protected AbstractClassJavaTypeDescriptor(Class<? extends T> type, MutabilityPlan<? extends T> mutabilityPlan) {
|
||||
this(
|
||||
type,
|
||||
mutabilityPlan,
|
||||
|
@ -64,13 +64,14 @@ public abstract class AbstractClassJavaTypeDescriptor<T> implements BasicJavaTyp
|
|||
* @param mutabilityPlan The plan for handling mutability aspects of the java type.
|
||||
* @param comparator The comparator for handling comparison of values
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected AbstractClassJavaTypeDescriptor(
|
||||
Class<T> type,
|
||||
MutabilityPlan<T> mutabilityPlan,
|
||||
Comparator<T> comparator) {
|
||||
this.type = type;
|
||||
this.mutabilityPlan = mutabilityPlan;
|
||||
this.comparator = comparator;
|
||||
Class<? extends T> type,
|
||||
MutabilityPlan<? extends T> mutabilityPlan,
|
||||
Comparator<? extends T> comparator) {
|
||||
this.type = (Class<T>) type;
|
||||
this.mutabilityPlan = (MutabilityPlan<T>) mutabilityPlan;
|
||||
this.comparator = (Comparator<T>) comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,11 +108,11 @@ public abstract class AbstractClassJavaTypeDescriptor<T> implements BasicJavaTyp
|
|||
return (value == null) ? "null" : value.toString();
|
||||
}
|
||||
|
||||
protected HibernateException unknownUnwrap(Class conversionType) {
|
||||
protected HibernateException unknownUnwrap(Class<?> conversionType) {
|
||||
return JavaTypeDescriptorHelper.unknownUnwrap( type, conversionType, this );
|
||||
}
|
||||
|
||||
protected HibernateException unknownWrap(Class conversionType) {
|
||||
protected HibernateException unknownWrap(Class<?> conversionType) {
|
||||
return JavaTypeDescriptorHelper.unknownWrap( conversionType, type, this );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,20 +15,22 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractTemporalJavaTypeDescriptor<T> extends AbstractClassJavaTypeDescriptor<T> implements TemporalJavaTypeDescriptor<T> {
|
||||
public abstract class AbstractTemporalJavaTypeDescriptor<T>
|
||||
extends AbstractClassJavaTypeDescriptor<T>
|
||||
implements TemporalJavaTypeDescriptor<T> {
|
||||
|
||||
protected AbstractTemporalJavaTypeDescriptor(Class<T> type) {
|
||||
protected AbstractTemporalJavaTypeDescriptor(Class<? extends T> type) {
|
||||
super( type );
|
||||
}
|
||||
|
||||
protected AbstractTemporalJavaTypeDescriptor(Class<T> type, MutabilityPlan<T> mutabilityPlan) {
|
||||
protected AbstractTemporalJavaTypeDescriptor(Class<? extends T> type, MutabilityPlan<? extends T> mutabilityPlan) {
|
||||
super( type, mutabilityPlan );
|
||||
}
|
||||
|
||||
public AbstractTemporalJavaTypeDescriptor(
|
||||
Class<T> type,
|
||||
MutabilityPlan<T> mutabilityPlan,
|
||||
Comparator<T> comparator) {
|
||||
Class<? extends T> type,
|
||||
MutabilityPlan<? extends T> mutabilityPlan,
|
||||
Comparator<? extends T> comparator) {
|
||||
super( type, mutabilityPlan, comparator );
|
||||
}
|
||||
|
||||
|
@ -62,19 +64,19 @@ public abstract class AbstractTemporalJavaTypeDescriptor<T> extends AbstractClas
|
|||
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forTimestampPrecision(TypeConfiguration typeConfiguration) {
|
||||
throw new UnsupportedOperationException(
|
||||
toString() + " as `jakarta.persistence.TemporalType.TIMESTAMP` not supported"
|
||||
this + " as `jakarta.persistence.TemporalType.TIMESTAMP` not supported"
|
||||
);
|
||||
}
|
||||
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forDatePrecision(TypeConfiguration typeConfiguration) {
|
||||
throw new UnsupportedOperationException(
|
||||
toString() + " as `jakarta.persistence.TemporalType.DATE` not supported"
|
||||
this + " as `jakarta.persistence.TemporalType.DATE` not supported"
|
||||
);
|
||||
}
|
||||
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forTimePrecision(TypeConfiguration typeConfiguration) {
|
||||
throw new UnsupportedOperationException(
|
||||
toString() + " as `jakarta.persistence.TemporalType.TIME` not supported"
|
||||
this + " as `jakarta.persistence.TemporalType.TIME` not supported"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,34 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
*/
|
||||
public interface JavaType<T> extends Serializable {
|
||||
/**
|
||||
* Get the Java type described
|
||||
* Get the Java type (Type) described
|
||||
*
|
||||
* @see #getJavaTypeClass
|
||||
*/
|
||||
default Type getJavaType() {
|
||||
// default on this side since #getJavaTypeClass is the currently implemented method
|
||||
return getJavaTypeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Java type (Class) described
|
||||
*
|
||||
* @see #getJavaType
|
||||
*/
|
||||
default Class<T> getJavaTypeClass() {
|
||||
return ReflectHelper.getClass( getJavaType() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given value an instance of the described type?
|
||||
*
|
||||
* Generally this comes down to {@link #getJavaTypeClass() getJavaTypeClass().}{@link Class#isInstance isInstance()},
|
||||
* though some descriptors (mainly the java.sql.Date, Time and Timestamp descriptors) might need different semantics
|
||||
*/
|
||||
default boolean isInstance(Object value) {
|
||||
return getJavaTypeClass().isInstance( value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the mutability plan for this Java type.
|
||||
*/
|
||||
|
@ -199,15 +220,6 @@ public interface JavaType<T> extends Serializable {
|
|||
return (T) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Java type handled here.
|
||||
*
|
||||
* @return The Java type.
|
||||
*/
|
||||
default Class<T> getJavaTypeClass() {
|
||||
return ReflectHelper.getClass( getJavaType() );
|
||||
}
|
||||
|
||||
/**
|
||||
* The check constraint that should be added to the column
|
||||
* definition in generated DDL.
|
||||
|
|
|
@ -15,18 +15,21 @@ import java.util.Calendar;
|
|||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link java.sql.Date} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @implSpec Unlike most {@link JavaType} implementations, can handle 2 different "domain
|
||||
* representations" (most map just a single type): general {@link Date} values in addition
|
||||
* to {@link java.sql.Date} values. This capability is shared with
|
||||
* {@link JdbcTimeJavaTypeDescriptor} and {@link JdbcTimestampJavaTypeDescriptor}.
|
||||
*/
|
||||
public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescriptor<Date> {
|
||||
public static final JdbcDateJavaTypeDescriptor INSTANCE = new JdbcDateJavaTypeDescriptor();
|
||||
|
@ -42,19 +45,9 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
@SuppressWarnings("unused")
|
||||
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||
|
||||
public static class DateMutabilityPlan extends MutableMutabilityPlan<Date> {
|
||||
public static final DateMutabilityPlan INSTANCE = new DateMutabilityPlan();
|
||||
@Override
|
||||
public Date deepCopyNotNull(Date value) {
|
||||
return value instanceof java.sql.Date
|
||||
? new java.sql.Date( value.getTime() )
|
||||
: new Date( value.getTime() );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public JdbcDateJavaTypeDescriptor() {
|
||||
super( Date.class, DateMutabilityPlan.INSTANCE );
|
||||
super( java.sql.Date.class, DateMutabilityPlan.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,29 +56,10 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
|
||||
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.DATE );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forDatePrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaTypeDescriptor<X>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Date value) {
|
||||
return new SimpleDateFormat( DATE_FORMAT ).format( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date fromString(CharSequence string) {
|
||||
try {
|
||||
return new Date( new SimpleDateFormat(DATE_FORMAT).parse( string.toString() ).getTime() );
|
||||
}
|
||||
catch ( ParseException pe) {
|
||||
throw new HibernateException( "could not parse date string" + string, pe );
|
||||
}
|
||||
public boolean isInstance(Object value) {
|
||||
// this check holds true for java.sql.Date as well
|
||||
return value instanceof Date
|
||||
&& !( value instanceof java.sql.Time );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,6 +67,7 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
if ( one == another ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( one == null || another == null ) {
|
||||
return false;
|
||||
}
|
||||
|
@ -101,8 +76,8 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
return true;
|
||||
}
|
||||
|
||||
Calendar calendar1 = Calendar.getInstance();
|
||||
Calendar calendar2 = Calendar.getInstance();
|
||||
final Calendar calendar1 = Calendar.getInstance();
|
||||
final Calendar calendar2 = Calendar.getInstance();
|
||||
calendar1.setTime( one );
|
||||
calendar2.setTime( another );
|
||||
|
||||
|
@ -113,7 +88,7 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
|
||||
@Override
|
||||
public int extractHashCode(Date value) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
final Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime( value );
|
||||
int hashCode = 1;
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.MONTH );
|
||||
|
@ -122,56 +97,80 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
return hashCode;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public <X> X unwrap(Date value, Class<X> type, WrapperOptions options) {
|
||||
public Date coerce(Object value, CoercionContext coercionContext) {
|
||||
return wrap( value, null );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object unwrap(Date value, Class type, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( LocalDate.class.isAssignableFrom( type ) ) {
|
||||
return unwrapLocalDate( value );
|
||||
}
|
||||
|
||||
if ( java.sql.Date.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Date rtn = value instanceof java.sql.Date
|
||||
? ( java.sql.Date ) value
|
||||
: new java.sql.Date( value.getTime() );
|
||||
return (X) rtn;
|
||||
return unwrapSqlDate( value );
|
||||
}
|
||||
if ( java.sql.Time.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Time rtn = value instanceof java.sql.Time
|
||||
? ( java.sql.Time ) value
|
||||
: new java.sql.Time( value.getTime() );
|
||||
return (X) rtn;
|
||||
|
||||
if ( java.util.Date.class.isAssignableFrom( type ) ) {
|
||||
return value;
|
||||
}
|
||||
if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Timestamp rtn = value instanceof java.sql.Timestamp
|
||||
? ( java.sql.Timestamp ) value
|
||||
: new java.sql.Timestamp( value.getTime() );
|
||||
return (X) rtn;
|
||||
|
||||
if ( Long.class.isAssignableFrom( type ) ) {
|
||||
return unwrapDateEpoch( value );
|
||||
}
|
||||
if ( Date.class.isAssignableFrom( type ) ) {
|
||||
return (X) value;
|
||||
|
||||
if ( String.class.isAssignableFrom( type ) ) {
|
||||
return toString( value );
|
||||
}
|
||||
|
||||
if ( Calendar.class.isAssignableFrom( type ) ) {
|
||||
final GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTimeInMillis( value.getTime() );
|
||||
return (X) cal;
|
||||
cal.setTimeInMillis( unwrapDateEpoch( value ) );
|
||||
return cal;
|
||||
}
|
||||
if ( Long.class.isAssignableFrom( type ) ) {
|
||||
return (X) Long.valueOf( value.getTime() );
|
||||
|
||||
if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) {
|
||||
return new java.sql.Timestamp( value.getTime() );
|
||||
}
|
||||
if ( LocalDate.class.isAssignableFrom( type ) ) {
|
||||
if ( value instanceof java.sql.Date ) {
|
||||
return (X) ( (java.sql.Date) value ).toLocalDate();
|
||||
}
|
||||
|
||||
if ( java.sql.Time.class.isAssignableFrom( type ) ) {
|
||||
throw new IllegalArgumentException( "Illegal attempt to treat `java.sql.Date` as `java.sql.Time`" );
|
||||
}
|
||||
|
||||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
private LocalDate unwrapLocalDate(Date value) {
|
||||
return value instanceof java.sql.Date
|
||||
? ( (java.sql.Date) value ).toLocalDate()
|
||||
: new java.sql.Date( value.getTime() ).toLocalDate();
|
||||
}
|
||||
|
||||
private java.sql.Date unwrapSqlDate(Date value) {
|
||||
return value instanceof java.sql.Date
|
||||
? (java.sql.Date) value
|
||||
: new java.sql.Date( value.getTime() );
|
||||
|
||||
}
|
||||
|
||||
private static long unwrapDateEpoch(Date value) {
|
||||
return value.getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> Date wrap(X value, WrapperOptions options) {
|
||||
public Date wrap(Object value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( value instanceof java.sql.Date ) {
|
||||
return (Date) value;
|
||||
return (java.sql.Date) value;
|
||||
}
|
||||
|
||||
if ( value instanceof Long ) {
|
||||
|
@ -192,4 +191,42 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Date value) {
|
||||
return new SimpleDateFormat( DATE_FORMAT ).format( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date fromString(CharSequence string) {
|
||||
try {
|
||||
return new java.sql.Date( new SimpleDateFormat(DATE_FORMAT).parse( string.toString() ).getTime() );
|
||||
}
|
||||
catch ( ParseException pe) {
|
||||
throw new HibernateException( "could not parse date string" + string, pe );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
|
||||
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.DATE );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forDatePrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaTypeDescriptor<X>) this;
|
||||
}
|
||||
|
||||
public static class DateMutabilityPlan extends MutableMutabilityPlan<Date> {
|
||||
public static final DateMutabilityPlan INSTANCE = new DateMutabilityPlan();
|
||||
@Override
|
||||
public Date deepCopyNotNull(Date value) {
|
||||
if ( value instanceof java.sql.Date ) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return new java.sql.Date( value.getTime() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@ import java.util.Calendar;
|
|||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
@ -25,10 +23,15 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Time} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @implSpec Unlike most {@link JavaType} implementations, can handle 2 different "domain
|
||||
* representations" (most map just a single type): general {@link Date} values in addition
|
||||
* to {@link Time} values. This capability is shared with
|
||||
* {@link JdbcDateJavaTypeDescriptor} and {@link JdbcTimestampJavaTypeDescriptor}.
|
||||
*/
|
||||
public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescriptor<Date> {
|
||||
public static final JdbcTimeJavaTypeDescriptor INSTANCE = new JdbcTimeJavaTypeDescriptor();
|
||||
|
@ -48,19 +51,9 @@ public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
@SuppressWarnings("unused")
|
||||
public static final DateTimeFormatter LOGGABLE_FORMATTER = DateTimeFormatter.ISO_LOCAL_TIME;
|
||||
|
||||
public static class TimeMutabilityPlan extends MutableMutabilityPlan<Date> {
|
||||
public static final TimeMutabilityPlan INSTANCE = new TimeMutabilityPlan();
|
||||
@Override
|
||||
public Date deepCopyNotNull(Date value) {
|
||||
return value instanceof Time
|
||||
? new Time( value.getTime() )
|
||||
: new Date( value.getTime() );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public JdbcTimeJavaTypeDescriptor() {
|
||||
super( Date.class, TimeMutabilityPlan.INSTANCE );
|
||||
super( Time.class, TimeMutabilityPlan.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,14 +62,125 @@ public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
|
||||
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIME );
|
||||
public boolean isInstance(Object value) {
|
||||
// this check holds true for java.sql.Time as well
|
||||
return value instanceof Date
|
||||
&& !( value instanceof java.sql.Date );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forTimePrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaTypeDescriptor<X>) this;
|
||||
public int extractHashCode(Date value) {
|
||||
final Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime( value );
|
||||
int hashCode = 1;
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.HOUR_OF_DAY );
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.MINUTE );
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.SECOND );
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.MILLISECOND );
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areEqual(Date one, Date another) {
|
||||
if ( one == another ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( one == null || another == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( one.getTime() == another.getTime() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Calendar calendar1 = Calendar.getInstance();
|
||||
final Calendar calendar2 = Calendar.getInstance();
|
||||
calendar1.setTime( one );
|
||||
calendar2.setTime( another );
|
||||
|
||||
return calendar1.get( Calendar.HOUR_OF_DAY ) == calendar2.get( Calendar.HOUR_OF_DAY )
|
||||
&& calendar1.get( Calendar.MINUTE ) == calendar2.get( Calendar.MINUTE )
|
||||
&& calendar1.get( Calendar.SECOND ) == calendar2.get( Calendar.SECOND )
|
||||
&& calendar1.get( Calendar.MILLISECOND ) == calendar2.get( Calendar.MILLISECOND );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date coerce(Object value, CoercionContext coercionContext) {
|
||||
return wrap( value, null );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object unwrap(Date value, Class type, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( LocalTime.class.isAssignableFrom( type ) ) {
|
||||
return value instanceof java.sql.Time
|
||||
? ( (java.sql.Time) value ).toLocalTime()
|
||||
: new java.sql.Time( value.getTime() ).toLocalTime();
|
||||
}
|
||||
|
||||
if ( Time.class.isAssignableFrom( type ) ) {
|
||||
return value instanceof Time
|
||||
? value
|
||||
: new Time( value.getTime() );
|
||||
}
|
||||
|
||||
if ( Date.class.isAssignableFrom( type ) ) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if ( Long.class.isAssignableFrom( type ) ) {
|
||||
return value.getTime();
|
||||
}
|
||||
|
||||
if ( String.class.isAssignableFrom( type ) ) {
|
||||
return toString( value );
|
||||
}
|
||||
|
||||
if ( Calendar.class.isAssignableFrom( type ) ) {
|
||||
final GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTimeInMillis( value.getTime() );
|
||||
return cal;
|
||||
}
|
||||
|
||||
if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) {
|
||||
return new java.sql.Timestamp( value.getTime() );
|
||||
}
|
||||
|
||||
if ( java.sql.Date.class.isAssignableFrom( type ) ) {
|
||||
throw new IllegalArgumentException( "Illegal attempt to treat `java.sql.Time` as `java.sql.Date`" );
|
||||
}
|
||||
|
||||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date wrap(Object value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( value instanceof LocalTime ) {
|
||||
return Time.valueOf( (LocalTime) value );
|
||||
}
|
||||
|
||||
if ( value instanceof Date ) {
|
||||
return (Date) value;
|
||||
}
|
||||
|
||||
if ( value instanceof Long ) {
|
||||
return new Time( (Long) value );
|
||||
}
|
||||
|
||||
if ( value instanceof Calendar ) {
|
||||
return new Time( ( (Calendar) value ).getTimeInMillis() );
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,113 +199,28 @@ public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
|
|||
}
|
||||
|
||||
@Override
|
||||
public int extractHashCode(Date value) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime( value );
|
||||
int hashCode = 1;
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.HOUR_OF_DAY );
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.MINUTE );
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.SECOND );
|
||||
hashCode = 31 * hashCode + calendar.get( Calendar.MILLISECOND );
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areEqual(Date one, Date another) {
|
||||
if ( one == another ) {
|
||||
return true;
|
||||
}
|
||||
if ( one == null || another == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( one.getTime() == another.getTime() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Calendar calendar1 = Calendar.getInstance();
|
||||
Calendar calendar2 = Calendar.getInstance();
|
||||
calendar1.setTime( one );
|
||||
calendar2.setTime( another );
|
||||
|
||||
return calendar1.get( Calendar.HOUR_OF_DAY ) == calendar2.get( Calendar.HOUR_OF_DAY )
|
||||
&& calendar1.get( Calendar.MINUTE ) == calendar2.get( Calendar.MINUTE )
|
||||
&& calendar1.get( Calendar.SECOND ) == calendar2.get( Calendar.SECOND )
|
||||
&& calendar1.get( Calendar.MILLISECOND ) == calendar2.get( Calendar.MILLISECOND );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public <X> X unwrap(Date value, Class<X> type, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( Time.class.isAssignableFrom( type ) ) {
|
||||
final Time rtn = value instanceof Time
|
||||
? ( Time ) value
|
||||
: new Time( value.getTime() );
|
||||
return (X) rtn;
|
||||
}
|
||||
if ( java.sql.Date.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Date rtn = value instanceof java.sql.Date
|
||||
? ( java.sql.Date ) value
|
||||
: new java.sql.Date( value.getTime() );
|
||||
return (X) rtn;
|
||||
}
|
||||
if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Timestamp rtn = value instanceof java.sql.Timestamp
|
||||
? ( java.sql.Timestamp ) value
|
||||
: new java.sql.Timestamp( value.getTime() );
|
||||
return (X) rtn;
|
||||
}
|
||||
if ( Date.class.isAssignableFrom( type ) ) {
|
||||
return (X) value;
|
||||
}
|
||||
if ( Calendar.class.isAssignableFrom( type ) ) {
|
||||
final GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTimeInMillis( value.getTime() );
|
||||
return (X) cal;
|
||||
}
|
||||
if ( Long.class.isAssignableFrom( type ) ) {
|
||||
return (X) Long.valueOf( value.getTime() );
|
||||
}
|
||||
if ( LocalTime.class.isAssignableFrom( type ) ) {
|
||||
if ( value instanceof Time ) {
|
||||
return (X) ( (Time) value ).toLocalTime();
|
||||
}
|
||||
}
|
||||
throw unknownUnwrap( type );
|
||||
}
|
||||
@Override
|
||||
public <X> Date wrap(X value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( value instanceof Time ) {
|
||||
return (Time) value;
|
||||
}
|
||||
|
||||
if ( value instanceof Long ) {
|
||||
return new Time( (Long) value );
|
||||
}
|
||||
|
||||
if ( value instanceof Calendar ) {
|
||||
return new Time( ( (Calendar) value ).getTimeInMillis() );
|
||||
}
|
||||
|
||||
if ( value instanceof Date ) {
|
||||
return new Time( ( (Date) value ).getTime() );
|
||||
}
|
||||
|
||||
if ( value instanceof LocalTime ) {
|
||||
return Time.valueOf( (LocalTime) value );
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
|
||||
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIME );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {
|
||||
return 0; //seconds (currently ignored since Dialects don't parameterize time type by precision)
|
||||
//seconds (currently ignored since Dialects don't parameterize time type by precision)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forTimePrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaTypeDescriptor<X>) this;
|
||||
}
|
||||
|
||||
|
||||
public static class TimeMutabilityPlan extends MutableMutabilityPlan<Date> {
|
||||
public static final TimeMutabilityPlan INSTANCE = new TimeMutabilityPlan();
|
||||
@Override
|
||||
public Date deepCopyNotNull(Date value) {
|
||||
return new Time( value.getTime() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.ZoneId;
|
||||
|
@ -31,7 +32,10 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
/**
|
||||
* Descriptor for {@link Timestamp} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @implSpec Unlike most {@link JavaType} implementations, can handle 2 different "domain
|
||||
* representations" (most map just a single type): general {@link Date} values in addition
|
||||
* to {@link Timestamp} values. This capability is shared with
|
||||
* {@link JdbcDateJavaTypeDescriptor} and {@link JdbcTimeJavaTypeDescriptor}.
|
||||
*/
|
||||
public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDescriptor<Date> implements VersionJavaType<Date> {
|
||||
public static final JdbcTimestampJavaTypeDescriptor INSTANCE = new JdbcTimestampJavaTypeDescriptor();
|
||||
|
@ -48,25 +52,9 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
|
|||
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ofPattern( TIMESTAMP_FORMAT )
|
||||
.withZone( ZoneId.from( ZoneOffset.UTC ) );
|
||||
|
||||
public static class TimestampMutabilityPlan extends MutableMutabilityPlan<Date> {
|
||||
public static final TimestampMutabilityPlan INSTANCE = new TimestampMutabilityPlan();
|
||||
@Override
|
||||
public Date deepCopyNotNull(Date value) {
|
||||
if ( value instanceof Timestamp ) {
|
||||
Timestamp orig = (Timestamp) value;
|
||||
Timestamp ts = new Timestamp( orig.getTime() );
|
||||
ts.setNanos( orig.getNanos() );
|
||||
return ts;
|
||||
}
|
||||
else {
|
||||
return new Date( value.getTime() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public JdbcTimestampJavaTypeDescriptor() {
|
||||
super( Date.class, TimestampMutabilityPlan.INSTANCE );
|
||||
super( Timestamp.class, TimestampMutabilityPlan.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,33 +63,9 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
|
||||
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forTimestampPrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaTypeDescriptor<X>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Date value) {
|
||||
return LITERAL_FORMATTER.format( value.toInstant() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date fromString(CharSequence string) {
|
||||
try {
|
||||
final TemporalAccessor accessor = LITERAL_FORMATTER.parse( string );
|
||||
return new Timestamp(
|
||||
accessor.getLong( ChronoField.INSTANT_SECONDS ) * 1000L
|
||||
+ accessor.get( ChronoField.NANO_OF_SECOND ) / 1_000_000
|
||||
);
|
||||
}
|
||||
catch ( DateTimeParseException pe) {
|
||||
throw new HibernateException( "could not parse timestamp string" + string, pe );
|
||||
}
|
||||
public boolean isInstance(Object value) {
|
||||
// this check holds true for java.sql.Timestamp as well
|
||||
return value instanceof Date;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -143,41 +107,50 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
|
|||
return Long.valueOf( value.getTime() / 1000 ).hashCode();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public <X> X unwrap(Date value, Class<X> type, WrapperOptions options) {
|
||||
public Date coerce(Object value, CoercionContext coercionContext) {
|
||||
return wrap( value, null );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Object unwrap(Date value, Class type, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( Timestamp.class.isAssignableFrom( type ) ) {
|
||||
final Timestamp rtn = value instanceof Timestamp
|
||||
? ( Timestamp ) value
|
||||
return value instanceof Timestamp
|
||||
? (Timestamp) value
|
||||
: new Timestamp( value.getTime() );
|
||||
return (X) rtn;
|
||||
}
|
||||
if ( java.sql.Date.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Date rtn = value instanceof java.sql.Date
|
||||
? ( java.sql.Date ) value
|
||||
: new java.sql.Date( value.getTime() );
|
||||
return (X) rtn;
|
||||
}
|
||||
if ( java.sql.Time.class.isAssignableFrom( type ) ) {
|
||||
final java.sql.Time rtn = value instanceof java.sql.Time
|
||||
? ( java.sql.Time ) value
|
||||
: new java.sql.Time( value.getTime() );
|
||||
return (X) rtn;
|
||||
}
|
||||
|
||||
if ( Date.class.isAssignableFrom( type ) ) {
|
||||
return (X) value;
|
||||
return value;
|
||||
}
|
||||
|
||||
if ( Calendar.class.isAssignableFrom( type ) ) {
|
||||
final GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTimeInMillis( value.getTime() );
|
||||
return (X) cal;
|
||||
return cal;
|
||||
}
|
||||
|
||||
if ( Long.class.isAssignableFrom( type ) ) {
|
||||
return (X) Long.valueOf( value.getTime() );
|
||||
return value.getTime();
|
||||
}
|
||||
|
||||
if ( java.sql.Date.class.isAssignableFrom( type ) ) {
|
||||
return value instanceof java.sql.Date
|
||||
? ( java.sql.Date ) value
|
||||
: new java.sql.Date( value.getTime() );
|
||||
}
|
||||
|
||||
if ( java.sql.Time.class.isAssignableFrom( type ) ) {
|
||||
return value instanceof java.sql.Time
|
||||
? ( java.sql.Time ) value
|
||||
: new java.sql.Time( value.getTime() );
|
||||
}
|
||||
|
||||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
|
@ -190,6 +163,10 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
|
|||
return (Timestamp) value;
|
||||
}
|
||||
|
||||
if ( value instanceof Date ) {
|
||||
return new Timestamp( ( (Date) value ).getTime() );
|
||||
}
|
||||
|
||||
if ( value instanceof Long ) {
|
||||
return new Timestamp( (Long) value );
|
||||
}
|
||||
|
@ -198,13 +175,39 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
|
|||
return new Timestamp( ( (Calendar) value ).getTimeInMillis() );
|
||||
}
|
||||
|
||||
if ( value instanceof Date ) {
|
||||
return new Timestamp( ( (Date) value ).getTime() );
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Date value) {
|
||||
return LITERAL_FORMATTER.format( value.toInstant() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date fromString(CharSequence string) {
|
||||
try {
|
||||
final TemporalAccessor accessor = LITERAL_FORMATTER.parse( string );
|
||||
return new Timestamp(
|
||||
accessor.getLong( ChronoField.INSTANT_SECONDS ) * 1000L
|
||||
+ accessor.get( ChronoField.NANO_OF_SECOND ) / 1_000_000
|
||||
);
|
||||
}
|
||||
catch ( DateTimeParseException pe) {
|
||||
throw new HibernateException( "could not parse timestamp string" + string, pe );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
|
||||
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> TemporalJavaTypeDescriptor<X> forTimestampPrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaTypeDescriptor<X>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {
|
||||
return dialect.getDefaultTimestampPrecision();
|
||||
|
@ -220,4 +223,21 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
|
|||
return new Timestamp( System.currentTimeMillis() );
|
||||
}
|
||||
|
||||
|
||||
public static class TimestampMutabilityPlan extends MutableMutabilityPlan<Date> {
|
||||
public static final TimestampMutabilityPlan INSTANCE = new TimestampMutabilityPlan();
|
||||
@Override
|
||||
public Date deepCopyNotNull(Date value) {
|
||||
if ( value instanceof Timestamp ) {
|
||||
// make sure to get the nanos
|
||||
final Timestamp orig = (Timestamp) value;
|
||||
final Timestamp copy = new Timestamp( orig.getTime() );
|
||||
copy.setNanos( orig.getNanos() );
|
||||
return copy;
|
||||
}
|
||||
else {
|
||||
return new Date( value.getTime() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.bootstrap.binding.annotations.basics;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
@ -61,7 +62,7 @@ public class SimpleEntityTypeResolutionsTests {
|
|||
case "someDate": {
|
||||
assertThat(
|
||||
propertyResolution.getDomainJavaDescriptor().getJavaTypeClass(),
|
||||
sameInstance( Date.class )
|
||||
sameInstance( Timestamp.class )
|
||||
);
|
||||
assertThat( propertyValue.getTemporalPrecision(), is( TemporalType.TIMESTAMP ) );
|
||||
break;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package org.hibernate.orm.test.type.descriptor.java;
|
||||
|
||||
import java.util.Date;
|
||||
import java.sql.Date;
|
||||
|
||||
import org.hibernate.type.descriptor.java.JdbcDateJavaTypeDescriptor;
|
||||
|
||||
import org.hibernate.testing.orm.junit.BaseUnitTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
@BaseUnitTest
|
||||
public class JdbcDateJavaTypeDescriptorTest {
|
||||
|
@ -15,7 +15,32 @@ public class JdbcDateJavaTypeDescriptorTest {
|
|||
@Test
|
||||
public void testToString() {
|
||||
final JdbcDateJavaTypeDescriptor javaTypeDescriptor = JdbcDateJavaTypeDescriptor.INSTANCE;
|
||||
final String actual = javaTypeDescriptor.toString( new Date( 0 ) );
|
||||
assertEquals( "01 January 1970", actual );
|
||||
|
||||
final String utilDate = javaTypeDescriptor.toString( new java.util.Date( 0 ) );
|
||||
assertThat( utilDate ).isEqualTo( "01 January 1970" );
|
||||
|
||||
final String sqlDate = javaTypeDescriptor.toString( new java.sql.Date( 0 ) );
|
||||
assertThat( sqlDate ).isEqualTo( "01 January 1970" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstance() {
|
||||
final JdbcDateJavaTypeDescriptor javaTypeDescriptor = JdbcDateJavaTypeDescriptor.INSTANCE;
|
||||
|
||||
javaTypeDescriptor.isInstance( new java.sql.Date( 0 ) );
|
||||
javaTypeDescriptor.isInstance( new java.util.Date( 0 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrap() {
|
||||
final JdbcDateJavaTypeDescriptor javaTypeDescriptor = JdbcDateJavaTypeDescriptor.INSTANCE;
|
||||
|
||||
final Date sqlDate = new Date( 0 );
|
||||
final java.util.Date wrappedSqlDate = javaTypeDescriptor.wrap( sqlDate, null );
|
||||
assertThat( wrappedSqlDate ).isSameAs( sqlDate );
|
||||
|
||||
final java.util.Date utilDate = new java.util.Date( 0 );
|
||||
final java.util.Date wrappedUtilDate = javaTypeDescriptor.wrap( utilDate, null );
|
||||
assertThat( wrappedUtilDate ).isInstanceOf( java.sql.Date.class );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue