HHH-17559 - Prefer Java Time handling for all temporal values
This commit is contained in:
parent
480072d4d1
commit
58173f92ee
|
@ -31,6 +31,7 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
|||
import org.hibernate.boot.registry.selector.spi.StrategySelectionException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.internal.NoCachingRegionFactory;
|
||||
import org.hibernate.cache.internal.StandardTimestampsCacheFactory;
|
||||
|
@ -216,6 +217,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private final SqmTranslatorFactory sqmTranslatorFactory;
|
||||
private final Boolean useOfJdbcNamedParametersEnabled;
|
||||
private boolean namedQueryStartupCheckingEnabled;
|
||||
private boolean preferJavaTimeJdbcTypes;
|
||||
private final int preferredSqlTypeCodeForBoolean;
|
||||
private final int preferredSqlTypeCodeForDuration;
|
||||
private final int preferredSqlTypeCodeForUuid;
|
||||
|
@ -428,6 +430,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
this.useOfJdbcNamedParametersEnabled = configurationService.getSetting( CALLABLE_NAMED_PARAMS_ENABLED, BOOLEAN, true );
|
||||
|
||||
this.namedQueryStartupCheckingEnabled = configurationService.getSetting( QUERY_STARTUP_CHECKING, BOOLEAN, true );
|
||||
this.preferJavaTimeJdbcTypes = MetadataBuildingContext.isPreferJavaTimeJdbcTypesEnabled( configurationService );
|
||||
this.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry );
|
||||
this.preferredSqlTypeCodeForDuration = ConfigurationHelper.getPreferredSqlTypeCodeForDuration( serviceRegistry );
|
||||
this.preferredSqlTypeCodeForUuid = ConfigurationHelper.getPreferredSqlTypeCodeForUuid( serviceRegistry );
|
||||
|
@ -1245,6 +1248,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return defaultTimeZoneStorageStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return preferJavaTimeJdbcTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormatMapper getJsonFormatMapper() {
|
||||
return jsonFormatMapper;
|
||||
|
|
|
@ -220,6 +220,11 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
return temporalPrecision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return buildingContext.isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return resolveJdbcTypeCode( buildingContext.getPreferredSqlTypeCodeForBoolean() );
|
||||
|
|
|
@ -60,6 +60,11 @@ public class VersionResolution<E> implements BasicValue.Resolution<E> {
|
|||
return TemporalType.TIMESTAMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return context.isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
|
||||
return BasicValue.timeZoneStorageStrategy( timeZoneStorageType, context );
|
||||
|
|
|
@ -477,6 +477,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
return delegate.getDefaultTimeZoneStorageStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return delegate.isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormatMapper getJsonFormatMapper() {
|
||||
return delegate.getJsonFormatMapper();
|
||||
|
|
|
@ -9,7 +9,10 @@ package org.hibernate.boot.spi;
|
|||
import org.hibernate.Incubating;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.cfg.MappingSettings;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* Describes the context in which the process of building {@link org.hibernate.boot.Metadata}
|
||||
|
@ -77,6 +80,24 @@ public interface MetadataBuildingContext {
|
|||
return ConfigurationHelper.getPreferredSqlTypeCodeForArray( getBootstrapContext().getServiceRegistry() );
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return isPreferJavaTimeJdbcTypesEnabled( getBootstrapContext().getServiceRegistry() );
|
||||
}
|
||||
|
||||
static boolean isPreferJavaTimeJdbcTypesEnabled(ServiceRegistry serviceRegistry) {
|
||||
return isPreferJavaTimeJdbcTypesEnabled( serviceRegistry.getService( ConfigurationService.class ) );
|
||||
}
|
||||
|
||||
static boolean isPreferJavaTimeJdbcTypesEnabled(ConfigurationService configurationService) {
|
||||
return ConfigurationHelper.getBoolean(
|
||||
MappingSettings.PREFER_JAVA_TYPE_JDBC_TYPES,
|
||||
configurationService.getSettings(),
|
||||
// todo : true would be better eventually so maybe just rip off that band aid
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
TypeDefinitionRegistry getTypeDefinitionRegistry();
|
||||
|
||||
/**
|
||||
|
|
|
@ -328,6 +328,8 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
|
|||
@Incubating
|
||||
TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy();
|
||||
|
||||
boolean isPreferJavaTimeJdbcTypesEnabled();
|
||||
|
||||
/**
|
||||
* The format mapper to use for serializing/deserializing JSON data.
|
||||
*
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.id.enhanced.ImplicitDatabaseObjectNamingStrategy;
|
|||
import org.hibernate.id.enhanced.StandardOptimizerDescriptor;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.type.WrapperArrayHandling;
|
||||
import org.hibernate.type.descriptor.jdbc.JavaTimeJdbcType;
|
||||
import org.hibernate.type.format.FormatMapper;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
|
@ -207,7 +208,8 @@ public interface MappingSettings {
|
|||
* {@link org.hibernate.annotations.JdbcTypeCode}, and friends.
|
||||
* <p>
|
||||
* Can also specify the name of the {@link org.hibernate.type.SqlTypes} constant
|
||||
* field, for example, {@code hibernate.type.preferred_instant_jdbc_type=TIMESTAMP}.
|
||||
* field, for example, {@code hibernate.type.preferred_instant_jdbc_type=TIMESTAMP}
|
||||
* or {@code hibernate.type.preferred_instant_jdbc_type=INSTANT}.
|
||||
*
|
||||
* @settingDefault {@link org.hibernate.type.SqlTypes#TIMESTAMP_UTC}.
|
||||
*
|
||||
|
@ -216,6 +218,28 @@ public interface MappingSettings {
|
|||
@Incubating
|
||||
String PREFERRED_INSTANT_JDBC_TYPE = "hibernate.type.preferred_instant_jdbc_type";
|
||||
|
||||
/**
|
||||
* Indicates whether to use {@linkplain java.time Java Time} references at the JDBC
|
||||
* boundary for binding and extracting temporal values to/from the database using
|
||||
* the support added in JDBC 4.2 via {@linkplain java.sql.PreparedStatement#setObject(int, Object, int)}
|
||||
* and {@linkplain java.sql.ResultSet#getObject(int, Class)}.
|
||||
* <p/>
|
||||
* Used to set the value across the entire system as opposed to scattered, individual
|
||||
* {@linkplain org.hibernate.annotations.JdbcTypeCode} and {@linkplain org.hibernate.annotations.JdbcType}
|
||||
* naming specific {@linkplain JavaTimeJdbcType} implementations.
|
||||
*
|
||||
* @implNote JDBC 4.2 does not define support for {@linkplain java.time.Instant}, so
|
||||
* {@linkplain java.time.Instant} is not included in this. Some drivers do implement support for this
|
||||
* even though not explicitly part of the JDBC specification. To use direct binding and extracting of
|
||||
* {@linkplain java.time.Instant} references, use {@code hibernate.type.preferred_instant_jdbc_type=INSTANT}.
|
||||
* See {@linkplain #PREFERRED_INSTANT_JDBC_TYPE}, {@linkplain org.hibernate.type.SqlTypes#INSTANT} and
|
||||
* {@linkplain org.hibernate.type.descriptor.jdbc.InstantJdbcType}.
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
@Incubating
|
||||
String PREFER_JAVA_TYPE_JDBC_TYPES = "hibernate.type.prefer_java_type_jdbc_types";
|
||||
|
||||
/**
|
||||
* Specifies a {@link org.hibernate.type.format.FormatMapper} used for JSON
|
||||
* serialization and deserialization, either:
|
||||
|
|
|
@ -46,7 +46,9 @@ public final class Versioning {
|
|||
public static Object seed(EntityVersionMapping versionMapping, SharedSessionContractImplementor session) {
|
||||
final Object seed = versionMapping.getJavaType().seed(
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
versionMapping.getTemporalPrecision() != null
|
||||
? versionMapping.getTemporalPrecision()
|
||||
: versionMapping.getPrecision(),
|
||||
versionMapping.getScale(),
|
||||
session
|
||||
);
|
||||
|
@ -165,7 +167,9 @@ public final class Versioning {
|
|||
final Object next = versionType.next(
|
||||
version,
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
versionMapping.getTemporalPrecision() != null
|
||||
? versionMapping.getTemporalPrecision()
|
||||
: versionMapping.getPrecision(),
|
||||
versionMapping.getScale(),
|
||||
session
|
||||
);
|
||||
|
|
|
@ -1105,6 +1105,11 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
return temporalPrecision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return getBuildingContext().isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object accept(ValueVisitor visitor) {
|
||||
return visitor.accept(this);
|
||||
|
|
|
@ -139,6 +139,13 @@ public interface SelectableConsumer {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
// we could probably use the details from `base`, but
|
||||
// this method should really never be called on this object
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomReadExpression() {
|
||||
return null;
|
||||
|
@ -204,6 +211,11 @@ public interface SelectableConsumer {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormula() {
|
||||
return false;
|
||||
|
|
|
@ -126,4 +126,9 @@ public interface SoftDeleteMapping extends SelectableMapping, VirtualModelPart,
|
|||
default Integer getScale() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
default Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ public interface SqlTypedMapping {
|
|||
Long getLength();
|
||||
Integer getPrecision();
|
||||
Integer getScale();
|
||||
Integer getTemporalPrecision();
|
||||
default boolean isLob() {
|
||||
return getJdbcMapping().getJdbcType().isLob();
|
||||
}
|
||||
|
@ -26,7 +27,12 @@ public interface SqlTypedMapping {
|
|||
default Size toSize() {
|
||||
final Size size = new Size();
|
||||
size.setLength( getLength() );
|
||||
if ( getTemporalPrecision() != null ) {
|
||||
size.setPrecision( getTemporalPrecision() );
|
||||
}
|
||||
else {
|
||||
size.setPrecision( getPrecision() );
|
||||
}
|
||||
size.setScale( getScale() );
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -283,6 +283,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
|
|||
final Long length;
|
||||
final Integer precision;
|
||||
final Integer scale;
|
||||
final Integer temporalPrecision;
|
||||
final boolean isLob;
|
||||
final boolean nullable;
|
||||
if ( selectable instanceof Column ) {
|
||||
|
@ -291,6 +292,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
|
|||
length = column.getLength();
|
||||
precision = column.getPrecision();
|
||||
scale = column.getScale();
|
||||
temporalPrecision = column.getTemporalPrecision();
|
||||
nullable = column.isNullable();
|
||||
isLob = column.isSqlTypeLob( creationProcess.getCreationContext().getMetadata() );
|
||||
selectablePath = basicValue.createSelectablePath( column.getQuotedName( dialect ) );
|
||||
|
@ -300,6 +302,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
|
|||
length = null;
|
||||
precision = null;
|
||||
scale = null;
|
||||
temporalPrecision = null;
|
||||
nullable = true;
|
||||
isLob = false;
|
||||
selectablePath = basicValue.createSelectablePath( bootPropertyDescriptor.getName() );
|
||||
|
@ -323,6 +326,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
|
|||
length,
|
||||
precision,
|
||||
scale,
|
||||
temporalPrecision,
|
||||
isLob,
|
||||
nullable,
|
||||
value.isColumnInsertable( 0 ),
|
||||
|
|
|
@ -183,6 +183,11 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
return precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getScale() {
|
||||
return scale;
|
||||
|
|
|
@ -152,6 +152,11 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return jdbcMapping;
|
||||
|
|
|
@ -50,6 +50,7 @@ public class BasicAttributeMapping
|
|||
|
||||
private final String tableExpression;
|
||||
private final String mappedColumnExpression;
|
||||
private final Integer temporalPrecision;
|
||||
private final SelectablePath selectablePath;
|
||||
private final boolean isFormula;
|
||||
private final String customReadExpression;
|
||||
|
@ -86,6 +87,7 @@ public class BasicAttributeMapping
|
|||
Long length,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Integer temporalPrecision,
|
||||
boolean isLob,
|
||||
boolean nullable,
|
||||
boolean insertable,
|
||||
|
@ -107,6 +109,7 @@ public class BasicAttributeMapping
|
|||
this.navigableRole = navigableRole;
|
||||
this.tableExpression = tableExpression;
|
||||
this.mappedColumnExpression = mappedColumnExpression;
|
||||
this.temporalPrecision = temporalPrecision;
|
||||
if ( selectablePath == null ) {
|
||||
this.selectablePath = new SelectablePath( mappedColumnExpression );
|
||||
}
|
||||
|
@ -186,6 +189,7 @@ public class BasicAttributeMapping
|
|||
selectableMapping.getLength(),
|
||||
selectableMapping.getPrecision(),
|
||||
selectableMapping.getScale(),
|
||||
selectableMapping.getTemporalPrecision(),
|
||||
selectableMapping.isLob(),
|
||||
selectableMapping.isNullable(),
|
||||
insertable,
|
||||
|
@ -292,6 +296,11 @@ public class BasicAttributeMapping
|
|||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return temporalPrecision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return tableExpression;
|
||||
|
|
|
@ -357,6 +357,11 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
return precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getScale() {
|
||||
return scale;
|
||||
|
|
|
@ -131,6 +131,11 @@ public class BasicValuedCollectionPart
|
|||
return selectableMapping.getPrecision();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return selectableMapping.getTemporalPrecision();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getScale() {
|
||||
return selectableMapping.getScale();
|
||||
|
|
|
@ -146,6 +146,11 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getScale() {
|
||||
return null;
|
||||
|
|
|
@ -135,6 +135,11 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return type;
|
||||
|
|
|
@ -379,6 +379,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
final Long length;
|
||||
final Integer precision;
|
||||
final Integer scale;
|
||||
final Integer temporalPrecision;
|
||||
final boolean isLob;
|
||||
final boolean nullable;
|
||||
if ( selectable instanceof Column ) {
|
||||
|
@ -387,6 +388,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
length = column.getLength();
|
||||
precision = column.getPrecision();
|
||||
scale = column.getScale();
|
||||
temporalPrecision = column.getTemporalPrecision();
|
||||
isLob = column.isSqlTypeLob( creationProcess.getCreationContext().getMetadata() );
|
||||
nullable = bootPropertyDescriptor.isOptional() && column.isNullable() ;
|
||||
selectablePath = basicValue.createSelectablePath( column.getQuotedName( dialect ) );
|
||||
|
@ -396,6 +398,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
length = null;
|
||||
precision = null;
|
||||
scale = null;
|
||||
temporalPrecision = null;
|
||||
isLob = false;
|
||||
nullable = bootPropertyDescriptor.isOptional();
|
||||
selectablePath = basicValue.createSelectablePath( bootPropertyDescriptor.getName() );
|
||||
|
@ -418,6 +421,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
length,
|
||||
precision,
|
||||
scale,
|
||||
temporalPrecision,
|
||||
isLob,
|
||||
nullable,
|
||||
insertability[columnPosition],
|
||||
|
|
|
@ -218,6 +218,11 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormula() {
|
||||
return false;
|
||||
|
|
|
@ -52,6 +52,7 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
|||
private final Long length;
|
||||
private final Integer precision;
|
||||
private final Integer scale;
|
||||
private final Integer temporalPrecision;
|
||||
|
||||
private final BasicType versionBasicType;
|
||||
|
||||
|
@ -69,6 +70,7 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
|||
Long length,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Integer temporalPrecision,
|
||||
BasicType<?> versionBasicType,
|
||||
EntityMappingType declaringType,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
|
@ -77,6 +79,7 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
|||
this.length = length;
|
||||
this.precision = precision;
|
||||
this.scale = scale;
|
||||
this.temporalPrecision = temporalPrecision;
|
||||
this.declaringType = declaringType;
|
||||
|
||||
this.columnTableExpression = columnTableExpression;
|
||||
|
@ -178,6 +181,11 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
|||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return temporalPrecision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return versionBasicType;
|
||||
|
|
|
@ -134,6 +134,11 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato
|
|||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormula() {
|
||||
return columnFormula != null;
|
||||
|
|
|
@ -194,6 +194,7 @@ public class MappingModelCreationHelper {
|
|||
Long length,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Integer temporalPrecision,
|
||||
boolean isLob,
|
||||
boolean nullable,
|
||||
boolean insertable,
|
||||
|
@ -244,6 +245,7 @@ public class MappingModelCreationHelper {
|
|||
length,
|
||||
precision,
|
||||
scale,
|
||||
temporalPrecision,
|
||||
isLob,
|
||||
nullable,
|
||||
insertable,
|
||||
|
|
|
@ -45,6 +45,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
|
|||
Long length,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Integer temporalPrecision,
|
||||
boolean isLob,
|
||||
boolean nullable,
|
||||
boolean insertable,
|
||||
|
@ -52,7 +53,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
|
|||
boolean partitioned,
|
||||
boolean isFormula,
|
||||
JdbcMapping jdbcMapping) {
|
||||
super( columnDefinition, length, precision, scale, jdbcMapping );
|
||||
super( columnDefinition, length, precision, scale, temporalPrecision, jdbcMapping );
|
||||
assert selectionExpression != null;
|
||||
// Save memory by using interned strings. Probability is high that we have multiple duplicate strings
|
||||
this.containingTableExpression = containingTableExpression == null ? null : containingTableExpression.intern();
|
||||
|
@ -168,6 +169,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
|
|||
final Long length;
|
||||
final Integer precision;
|
||||
final Integer scale;
|
||||
final Integer temporalPrecision;
|
||||
final String selectableName;
|
||||
final boolean isLob;
|
||||
final boolean isNullable;
|
||||
|
@ -177,6 +179,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
|
|||
length = null;
|
||||
precision = null;
|
||||
scale = null;
|
||||
temporalPrecision = null;
|
||||
isNullable = true;
|
||||
isLob = false;
|
||||
selectableName = selectable.getText();
|
||||
|
@ -188,6 +191,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
|
|||
length = column.getLength();
|
||||
precision = column.getPrecision();
|
||||
scale = column.getScale();
|
||||
temporalPrecision = column.getTemporalPrecision();
|
||||
|
||||
isNullable = forceNotNullable ? false : column.isNullable();
|
||||
isLob = column.isSqlTypeLob( creationContext.getMetadata() );
|
||||
|
@ -205,6 +209,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
|
|||
length,
|
||||
precision,
|
||||
scale,
|
||||
temporalPrecision,
|
||||
isLob,
|
||||
isNullable,
|
||||
insertable,
|
||||
|
|
|
@ -663,6 +663,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
return keySide.getModelPart().getScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return keySide.getModelPart().getTemporalPrecision();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFetchableName() {
|
||||
return PART_NAME;
|
||||
|
|
|
@ -18,6 +18,7 @@ public class SqlTypedMappingImpl implements SqlTypedMapping {
|
|||
private final Long length;
|
||||
private final Integer precision;
|
||||
private final Integer scale;
|
||||
private final Integer temporalPrecision;
|
||||
private final JdbcMapping jdbcMapping;
|
||||
|
||||
public SqlTypedMappingImpl(
|
||||
|
@ -25,12 +26,14 @@ public class SqlTypedMappingImpl implements SqlTypedMapping {
|
|||
Long length,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Integer temporalPrecision,
|
||||
JdbcMapping jdbcMapping) {
|
||||
// Save memory by using interned strings. Probability is high that we have multiple duplicate strings
|
||||
this.columnDefinition = columnDefinition == null ? null : columnDefinition.intern();
|
||||
this.length = length;
|
||||
this.precision = precision;
|
||||
this.scale = scale;
|
||||
this.temporalPrecision = temporalPrecision;
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
}
|
||||
|
||||
|
@ -49,6 +52,11 @@ public class SqlTypedMappingImpl implements SqlTypedMapping {
|
|||
return precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return temporalPrecision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getScale() {
|
||||
return scale;
|
||||
|
|
|
@ -2088,7 +2088,9 @@ public abstract class AbstractEntityPersister
|
|||
final Object nextVersion = getVersionJavaType().next(
|
||||
currentVersion,
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
versionMapping.getTemporalPrecision() != null
|
||||
? versionMapping.getTemporalPrecision()
|
||||
: versionMapping.getPrecision(),
|
||||
versionMapping.getScale(),
|
||||
session
|
||||
);
|
||||
|
@ -5506,6 +5508,7 @@ public abstract class AbstractEntityPersister
|
|||
column.getLength(),
|
||||
column.getPrecision(),
|
||||
column.getScale(),
|
||||
column.getTemporalPrecision(),
|
||||
basicTypeResolution.getLegacyResolvedBasicType(),
|
||||
entityPersister,
|
||||
creationProcess
|
||||
|
@ -5551,6 +5554,7 @@ public abstract class AbstractEntityPersister
|
|||
column.getLength(),
|
||||
column.getPrecision(),
|
||||
column.getScale(),
|
||||
column.getTemporalPrecision(),
|
||||
column.isSqlTypeLob( creationProcess.getCreationContext().getMetadata() ),
|
||||
column.isNullable(),
|
||||
value.isColumnInsertable( 0 ),
|
||||
|
@ -5570,6 +5574,7 @@ public abstract class AbstractEntityPersister
|
|||
final Long length;
|
||||
final Integer precision;
|
||||
final Integer scale;
|
||||
final Integer temporalPrecision;
|
||||
final boolean isLob;
|
||||
final boolean nullable;
|
||||
|
||||
|
@ -5582,6 +5587,7 @@ public abstract class AbstractEntityPersister
|
|||
columnDefinition = column.getSqlType();
|
||||
length = column.getLength();
|
||||
precision = column.getPrecision();
|
||||
temporalPrecision = column.getTemporalPrecision();
|
||||
scale = column.getScale();
|
||||
isLob = column.isSqlTypeLob( creationProcess.getCreationContext().getMetadata() );
|
||||
nullable = column.isNullable();
|
||||
|
@ -5609,6 +5615,7 @@ public abstract class AbstractEntityPersister
|
|||
columnDefinition = column.getSqlType();
|
||||
length = column.getLength();
|
||||
precision = column.getPrecision();
|
||||
temporalPrecision = column.getTemporalPrecision();
|
||||
scale = column.getScale();
|
||||
nullable = column.isNullable();
|
||||
isLob = column.isSqlTypeLob( creationContext.getMetadata() );
|
||||
|
@ -5622,6 +5629,7 @@ public abstract class AbstractEntityPersister
|
|||
columnDefinition = null;
|
||||
length = null;
|
||||
precision = null;
|
||||
temporalPrecision = null;
|
||||
scale = null;
|
||||
nullable = true;
|
||||
isLob = false;
|
||||
|
@ -5646,6 +5654,7 @@ public abstract class AbstractEntityPersister
|
|||
length,
|
||||
precision,
|
||||
scale,
|
||||
temporalPrecision,
|
||||
isLob,
|
||||
nullable,
|
||||
value.isColumnInsertable( 0 ),
|
||||
|
|
|
@ -379,6 +379,11 @@ public class EntityTableMapping implements TableMapping {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomReadExpression() {
|
||||
return null;
|
||||
|
|
|
@ -176,6 +176,11 @@ public class AnonymousTupleBasicValuedModelPart implements OwnedValuedModelPart,
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getMappedType() {
|
||||
return this;
|
||||
|
|
|
@ -899,12 +899,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
persister.getVersionJavaType().next(
|
||||
persister.getVersionJavaType().seed(
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
versionMapping.getTemporalPrecision() != null
|
||||
? versionMapping.getTemporalPrecision()
|
||||
: versionMapping.getPrecision(),
|
||||
versionMapping.getScale(),
|
||||
null
|
||||
),
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
versionMapping.getTemporalPrecision() != null
|
||||
? versionMapping.getTemporalPrecision()
|
||||
: versionMapping.getPrecision(),
|
||||
versionMapping.getScale(),
|
||||
null
|
||||
),
|
||||
|
@ -6072,6 +6076,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
null,
|
||||
precision,
|
||||
0,
|
||||
null,
|
||||
( (BasicType<?>) bindable ).getJdbcMapping()
|
||||
);
|
||||
}
|
||||
|
@ -6082,6 +6087,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
null,
|
||||
bigDecimal.precision(),
|
||||
bigDecimal.scale(),
|
||||
null,
|
||||
( (BasicType<?>) bindable ).getJdbcMapping()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5755,7 +5755,9 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
parameter.getJdbcMapping(),
|
||||
sqlTypedMapping.getColumnDefinition(),
|
||||
sqlTypedMapping.getLength(),
|
||||
sqlTypedMapping.getPrecision(),
|
||||
sqlTypedMapping.getTemporalPrecision() != null
|
||||
? sqlTypedMapping.getTemporalPrecision()
|
||||
: sqlTypedMapping.getPrecision(),
|
||||
sqlTypedMapping.getScale()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,11 @@ public class CastTarget implements Expression, SqlAstNode, SqlTypedMapping {
|
|||
return precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTemporalPrecision() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Integer getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,9 @@ public class VersionTypeSeedParameterSpecification extends AbstractJdbcParameter
|
|||
statement,
|
||||
versionMapping.getJavaType().seed(
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
versionMapping.getTemporalPrecision() != null
|
||||
? versionMapping.getTemporalPrecision()
|
||||
: versionMapping.getPrecision(),
|
||||
versionMapping.getScale(),
|
||||
executionContext.getSession()
|
||||
),
|
||||
|
|
|
@ -498,6 +498,80 @@ public class SqlTypes {
|
|||
*/
|
||||
public static final int TIME_UTC = 3007;
|
||||
|
||||
|
||||
// Java Time (java.time) "virtual" JdbcTypes
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.Instant}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.InstantJdbcType
|
||||
*/
|
||||
public static final int INSTANT = 3008;
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.LocalDateTime}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.LocalDateTimeJdbcType
|
||||
*/
|
||||
public static final int LOCAL_DATE_TIME = 3009;
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.LocalDate}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.LocalDateJdbcType
|
||||
*/
|
||||
public static final int LOCAL_DATE = 3010;
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.LocalTime}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.LocalTimeJdbcType
|
||||
*/
|
||||
public static final int LOCAL_TIME = 3011;
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.OffsetDateTime}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.OffsetDateTimeJdbcType
|
||||
*/
|
||||
public static final int OFFSET_DATE_TIME = 3012;
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.OffsetTime}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.OffsetTimeJdbcType
|
||||
*/
|
||||
public static final int OFFSET_TIME = 3013;
|
||||
|
||||
/**
|
||||
* A type code representing a "virtual mapping" of {@linkplain java.time.ZonedDateTime}
|
||||
* as a JDBC type using {@linkplain java.sql.ResultSet#getObject} and
|
||||
* {@linkplain java.sql.PreparedStatement#setObject} which JDBC requires compliant
|
||||
* drivers to support.
|
||||
*
|
||||
* @see org.hibernate.type.descriptor.jdbc.ZonedDateTimeJdbcType
|
||||
*/
|
||||
public static final int ZONED_DATE_TIME = 3014;
|
||||
|
||||
|
||||
// Interval types
|
||||
|
||||
/**
|
||||
|
@ -766,6 +840,7 @@ public class SqlTypes {
|
|||
case TIMESTAMP:
|
||||
case TIMESTAMP_WITH_TIMEZONE:
|
||||
case TIMESTAMP_UTC:
|
||||
case INSTANT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.GregorianCalendar;
|
|||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
@ -47,6 +48,9 @@ public class LocalDateJavaType extends AbstractTemporalJavaType<LocalDate> {
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
|
||||
if ( context.isPreferJavaTimeJdbcTypesEnabled() ) {
|
||||
return context.getJdbcType( SqlTypes.LOCAL_DATE );
|
||||
}
|
||||
return context.getJdbcType( Types.DATE );
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import jakarta.persistence.TemporalType;
|
|||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
@ -48,6 +49,9 @@ public class LocalDateTimeJavaType extends AbstractTemporalJavaType<LocalDateTim
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
|
||||
if ( context.isPreferJavaTimeJdbcTypesEnabled() ) {
|
||||
return context.getJdbcType( SqlTypes.LOCAL_DATE_TIME );
|
||||
}
|
||||
return context.getJdbcType( Types.TIMESTAMP );
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.GregorianCalendar;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.DateTimeUtils;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -52,6 +53,9 @@ public class LocalTimeJavaType extends AbstractTemporalJavaType<LocalTime> {
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
|
||||
if ( context.isPreferJavaTimeJdbcTypesEnabled() ) {
|
||||
return context.getJdbcType( SqlTypes.LOCAL_TIME );
|
||||
}
|
||||
return context.getJdbcType( Types.TIME );
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.GregorianCalendar;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.CharSequenceHelper;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
@ -69,8 +70,10 @@ public class OffsetDateTimeJavaType extends AbstractTemporalJavaType<OffsetDateT
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators stdIndicators) {
|
||||
return stdIndicators.getTypeConfiguration().getJdbcTypeRegistry()
|
||||
.getDescriptor( stdIndicators.getDefaultZonedTimestampSqlType() );
|
||||
if ( stdIndicators.isPreferJavaTimeJdbcTypesEnabled() ) {
|
||||
return stdIndicators.getJdbcType( SqlTypes.OFFSET_DATE_TIME );
|
||||
}
|
||||
return stdIndicators.getJdbcType( stdIndicators.getDefaultZonedTimestampSqlType() );
|
||||
}
|
||||
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.type.descriptor.java;
|
|||
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
@ -21,15 +20,16 @@ import java.util.Calendar;
|
|||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.DateTimeUtils;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Java type descriptor for the {@link OffsetTime} type.
|
||||
*
|
||||
|
@ -52,8 +52,10 @@ public class OffsetTimeJavaType extends AbstractTemporalJavaType<OffsetTime> {
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators stdIndicators) {
|
||||
return stdIndicators.getTypeConfiguration().getJdbcTypeRegistry()
|
||||
.getDescriptor( stdIndicators.getDefaultZonedTimeSqlType() );
|
||||
if ( stdIndicators.isPreferJavaTimeJdbcTypesEnabled() ) {
|
||||
return stdIndicators.getJdbcType( SqlTypes.OFFSET_TIME );
|
||||
}
|
||||
return stdIndicators.getJdbcType( stdIndicators.getDefaultZonedTimeSqlType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,6 +21,7 @@ import jakarta.persistence.TemporalType;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.ZonedDateTimeComparator;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
@ -50,8 +51,10 @@ public class ZonedDateTimeJavaType extends AbstractTemporalJavaType<ZonedDateTim
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators stdIndicators) {
|
||||
return stdIndicators.getTypeConfiguration().getJdbcTypeRegistry()
|
||||
.getDescriptor( stdIndicators.getDefaultZonedTimestampSqlType() );
|
||||
if ( stdIndicators.isPreferJavaTimeJdbcTypesEnabled() ) {
|
||||
return stdIndicators.getJdbcType( SqlTypes.ZONED_DATE_TIME );
|
||||
}
|
||||
return stdIndicators.getJdbcType( stdIndicators.getDefaultZonedTimestampSqlType() );
|
||||
}
|
||||
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
|
|
|
@ -42,6 +42,11 @@ public class DelegatingJdbcTypeIndicators implements JdbcTypeIndicators {
|
|||
return delegate.getTemporalPrecision();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return delegate.isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return delegate.getPreferredSqlTypeCodeForBoolean();
|
||||
|
|
|
@ -6,15 +6,39 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.jdbc;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link SqlTypes#TIMESTAMP_UTC TIMESTAMP_UTC} handling.
|
||||
* Descriptor for handling {@linkplain Instant} directly through the JDBC driver
|
||||
*
|
||||
* @deprecated Use {@link TimestampUtcAsInstantJdbcType}
|
||||
* @author Christian Beikov
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class InstantJdbcType extends TimestampUtcAsInstantJdbcType {
|
||||
public class InstantJdbcType extends AbstractJavaTimeJdbcType<Instant> {
|
||||
public static final InstantJdbcType INSTANCE = new InstantJdbcType();
|
||||
|
||||
public InstantJdbcType() {
|
||||
super( Instant.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.INSTANT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TIMESTAMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIMESTAMP );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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.jdbc;
|
||||
|
||||
/**
|
||||
* Common marker interface for mapping {@linkplain java.time Java Time} objects
|
||||
* directly through the JDBC driver.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JavaTimeJdbcType extends JdbcType {
|
||||
|
||||
}
|
|
@ -69,6 +69,13 @@ public interface JdbcTypeIndicators {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.MappingSettings#PREFER_JAVA_TYPE_JDBC_TYPES
|
||||
*/
|
||||
default boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return getCurrentBaseSqlTypeIndicators().isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* When mapping a boolean type to the database what is the preferred SQL type code to use?
|
||||
* <p>
|
||||
|
|
|
@ -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.descriptor.jdbc;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for handling {@linkplain LocalDate} directly through the JDBC driver
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalDateJdbcType extends AbstractJavaTimeJdbcType<LocalDate> {
|
||||
public static LocalDateJdbcType INSTANCE = new LocalDateJdbcType();
|
||||
|
||||
public LocalDateJdbcType() {
|
||||
super( LocalDate.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.LOCAL_DATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.DATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.DATE );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.jdbc;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.SetObjectBinder;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for handling {@linkplain LocalDateTime} directly through the JDBC driver
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalDateTimeJdbcType extends AbstractJavaTimeJdbcType<LocalDateTime> {
|
||||
public static LocalDateTimeJdbcType INSTANCE = new LocalDateTimeJdbcType();
|
||||
|
||||
public LocalDateTimeJdbcType() {
|
||||
super( LocalDateTime.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.LOCAL_DATE_TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TIMESTAMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIMESTAMP );
|
||||
}
|
||||
}
|
|
@ -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.descriptor.jdbc;
|
||||
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for handling {@linkplain LocalTime} directly through the JDBC driver
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalTimeJdbcType extends AbstractJavaTimeJdbcType<LocalTime> {
|
||||
public static LocalTimeJdbcType INSTANCE = new LocalTimeJdbcType();
|
||||
|
||||
public LocalTimeJdbcType() {
|
||||
super( LocalTime.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.LOCAL_TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIME );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.jdbc;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for handling {@linkplain OffsetDateTime} directly through the JDBC driver
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OffsetDateTimeJdbcType extends AbstractJavaTimeJdbcType<OffsetDateTime> {
|
||||
public static OffsetDateTimeJdbcType INSTANCE = new OffsetDateTimeJdbcType();
|
||||
|
||||
public OffsetDateTimeJdbcType() {
|
||||
super( OffsetDateTime.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.OFFSET_DATE_TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIMESTAMP );
|
||||
}
|
||||
}
|
|
@ -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.descriptor.jdbc;
|
||||
|
||||
import java.time.OffsetTime;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for handling {@linkplain OffsetTime} directly through the JDBC driver
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OffsetTimeJdbcType extends AbstractJavaTimeJdbcType<OffsetTime> {
|
||||
public static OffsetTimeJdbcType INSTANCE = new OffsetTimeJdbcType();
|
||||
|
||||
public OffsetTimeJdbcType() {
|
||||
super( OffsetTime.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.OFFSET_TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TIME_WITH_TIMEZONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIME );
|
||||
}
|
||||
}
|
|
@ -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.descriptor.jdbc;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.AbstractJavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* Descriptor for handling {@linkplain ZonedDateTime} directly through the JDBC driver
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ZonedDateTimeJdbcType extends AbstractJavaTimeJdbcType<ZonedDateTime> {
|
||||
public static ZonedDateTimeJdbcType INSTANCE = new ZonedDateTimeJdbcType();
|
||||
|
||||
public ZonedDateTimeJdbcType() {
|
||||
super( ZonedDateTime.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.ZONED_DATE_TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIMESTAMP );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.jdbc.internal;
|
||||
|
||||
import java.time.temporal.Temporal;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JavaTimeJdbcType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractJavaTimeJdbcType<T extends Temporal> implements JavaTimeJdbcType {
|
||||
private final Class<T> javaTimeType;
|
||||
|
||||
public AbstractJavaTimeJdbcType(Class<T> javaTimeType) {
|
||||
this.javaTimeType = javaTimeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getPreferredJavaTypeClass(WrapperOptions options) {
|
||||
return javaTimeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> JavaType<X> getJdbcRecommendedJavaTypeMapping(
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor( javaTimeType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
|
||||
return new SetObjectBinder<>( javaType, this, javaTimeType, getDdlTypeCode() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
|
||||
return new GetObjectExtractor<>( javaType, this, javaTimeType );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.jdbc.internal;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.descriptor.jdbc.JavaTimeJdbcType;
|
||||
|
||||
/**
|
||||
* Support for extracting values directly through `getObject` JDBC driver calls.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GetObjectExtractor<T> extends BasicExtractor<T> {
|
||||
private final Class<?> baseClass;
|
||||
|
||||
public GetObjectExtractor(JavaType<T> javaType, JavaTimeJdbcType jdbcType, Class<?> baseClass) {
|
||||
super( javaType, jdbcType );
|
||||
this.baseClass = baseClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T doExtract(
|
||||
ResultSet rs,
|
||||
int paramIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
return getJavaType().wrap( rs.getObject( paramIndex, baseClass ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T doExtract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
|
||||
return getJavaType().wrap( statement.getObject( paramIndex, baseClass ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
|
||||
return getJavaType().wrap( statement.getObject( name, baseClass ), options );
|
||||
}
|
||||
}
|
|
@ -19,11 +19,17 @@ import org.hibernate.type.descriptor.jdbc.DateJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.DecimalJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.DoubleJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.FloatJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.InstantJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.IntegerJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalDateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalDateTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LongVarbinaryJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LongVarcharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NumericJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.OffsetDateTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.OffsetTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.RealJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.RowIdJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
|
@ -34,6 +40,7 @@ import org.hibernate.type.descriptor.jdbc.TimestampWithTimeZoneJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.TinyIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ZonedDateTimeJdbcType;
|
||||
|
||||
/**
|
||||
* Registers the base {@link JdbcType} instances.
|
||||
|
@ -61,6 +68,14 @@ public class JdbcTypeBaseline {
|
|||
target.addDescriptor( SmallIntJdbcType.INSTANCE );
|
||||
target.addDescriptor( TinyIntJdbcType.INSTANCE );
|
||||
|
||||
target.addDescriptor( InstantJdbcType.INSTANCE );
|
||||
target.addDescriptor( LocalDateTimeJdbcType.INSTANCE );
|
||||
target.addDescriptor( LocalDateJdbcType.INSTANCE );
|
||||
target.addDescriptor( LocalTimeJdbcType.INSTANCE );
|
||||
target.addDescriptor( OffsetDateTimeJdbcType.INSTANCE );
|
||||
target.addDescriptor( OffsetTimeJdbcType.INSTANCE );
|
||||
target.addDescriptor( ZonedDateTimeJdbcType.INSTANCE );
|
||||
|
||||
target.addDescriptor( DateJdbcType.INSTANCE );
|
||||
target.addDescriptor( TimestampJdbcType.INSTANCE );
|
||||
target.addDescriptor( TimestampWithTimeZoneJdbcType.INSTANCE );
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.jdbc.internal;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* Support for binding values directly through `setObject` JDBC driver calls.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SetObjectBinder<T> extends BasicBinder<T> {
|
||||
private final Class<?> baseClass;
|
||||
private final int jdbcTypeCode;
|
||||
|
||||
public SetObjectBinder(
|
||||
JavaType<T> javaType,
|
||||
JdbcType jdbcType,
|
||||
Class<?> baseClass,
|
||||
int jdbcTypeCode) {
|
||||
super( javaType, jdbcType );
|
||||
this.baseClass = baseClass;
|
||||
this.jdbcTypeCode = jdbcTypeCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, T value, int index, WrapperOptions options) throws SQLException {
|
||||
st.setObject( index, normalize( value, options ), jdbcTypeCode );
|
||||
}
|
||||
|
||||
protected Object normalize(T value, WrapperOptions options) {
|
||||
return getJavaType().unwrap( value, baseClass, options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, T value, String name, WrapperOptions options) throws SQLException {
|
||||
st.setObject( name, normalize( value, options ), jdbcTypeCode );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
|
||||
st.setNull( index, jdbcTypeCode );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
|
||||
st.setNull( name, jdbcTypeCode );
|
||||
}
|
||||
}
|
|
@ -416,6 +416,13 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
|
|||
return typeConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return sessionFactory == null
|
||||
? metadataBuildingContext.isPreferJavaTimeJdbcTypesEnabled()
|
||||
: sessionFactory.getSessionFactoryOptions().isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
|
||||
return sessionFactory == null
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.javatime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.cfg.MappingSettings;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.LocalDateJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalDateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalDateTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalTimeJdbcType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
|
||||
|
||||
/**
|
||||
* Tests for "direct" JDBC handling of {@linkplain java.time Java Time} types.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||
@ServiceRegistry(
|
||||
settings = @Setting(name = MappingSettings.PREFER_JAVA_TYPE_JDBC_TYPES, value = "true")
|
||||
)
|
||||
@DomainModel( annotatedClasses = GlobalJavaTimeJdbcTypeTests.EntityWithJavaTimeValues.class )
|
||||
@SessionFactory
|
||||
@SkipForDialect( dialectClass = SybaseDialect.class, reason = "Sybase drivers do not comply with JDBC 4.2 requirements for support of Java Time objects", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = DB2Dialect.class, reason = "DB2 drivers do not comply with JDBC 4.2 requirements for support of Java Time objects", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = DerbyDialect.class, reason = "Derby drivers do not comply with JDBC 4.2 requirements for support of Java Time objects" )
|
||||
public class GlobalJavaTimeJdbcTypeTests {
|
||||
@Test
|
||||
void testMappings(DomainModelScope scope) {
|
||||
final PersistentClass entityBinding = scope.getEntityBinding( EntityWithJavaTimeValues.class );
|
||||
|
||||
checkAttribute( entityBinding, "theLocalDate", LocalDateJdbcType.class );
|
||||
checkAttribute( entityBinding, "theLocalDateTime", LocalDateTimeJdbcType.class );
|
||||
checkAttribute( entityBinding, "theLocalTime", LocalTimeJdbcType.class );
|
||||
}
|
||||
|
||||
private void checkAttribute(
|
||||
PersistentClass entityBinding,
|
||||
String attributeName,
|
||||
Class<? extends JavaTimeJdbcType> expectedJdbcTypeDescriptorType) {
|
||||
final Property property = entityBinding.getProperty( attributeName );
|
||||
final BasicValue value = (BasicValue) property.getValue();
|
||||
final BasicValue.Resolution<?> resolution = value.resolve();
|
||||
final JdbcType jdbcType = resolution.getJdbcType();
|
||||
assertThat( jdbcType ).isInstanceOf( expectedJdbcTypeDescriptorType );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInstant(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final Instant start = roundToDefaultPrecision( Instant.EPOCH, dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theInstant = start;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theInstant ).isEqualTo( start );
|
||||
entity.theInstant = start.plus( 2000, ChronoUnit.DAYS );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theInstant ).isEqualTo( start.plus( 2000, ChronoUnit.DAYS ) );
|
||||
entity.theInstant = start.minus( 2000, ChronoUnit.DAYS );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theInstant ).isEqualTo( start.minus( 2000, ChronoUnit.DAYS ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLocalDateTime(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final LocalDateTime start = roundToDefaultPrecision( LocalDateTime.now(), dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theLocalDateTime = start;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDateTime ).isEqualTo( start );
|
||||
entity.theLocalDateTime = start.plusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDateTime ).isEqualTo( start.plusDays( 2000 ) );
|
||||
entity.theLocalDateTime = start.minusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDateTime ).isEqualTo( start.minusDays( 2000 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLocalDate(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final LocalDate startTime = roundToDefaultPrecision( LocalDate.now(), dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theLocalDate = startTime;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDate ).isEqualTo( startTime );
|
||||
entity.theLocalDate = startTime.plusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDate ).isEqualTo( startTime.plusDays( 2000 ) );
|
||||
entity.theLocalDate = startTime.minusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDate ).isEqualTo( startTime.minusDays( 2000 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect( dialectClass = OracleDialect.class, reason = "Oracle drivers truncate fractional seconds from the LocalTime", matchSubTypes = true)
|
||||
void testLocalTime(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final LocalTime startTime = roundToDefaultPrecision( LocalTime.now(), dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theLocalTime = startTime;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalTime ).isEqualTo( startTime );
|
||||
entity.theLocalTime = startTime.plusHours( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalTime ).isEqualTo( startTime.plusHours( 2000 ) );
|
||||
entity.theLocalTime = startTime.plusHours( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalTime ).isEqualTo( startTime.plusHours( 2000 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createMutationQuery( "delete EntityWithJavaTimeValues" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name="EntityWithJavaTimeValues")
|
||||
@Table(name="EntityWithJavaTimeValues")
|
||||
public static class EntityWithJavaTimeValues {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
private Instant theInstant;
|
||||
|
||||
private LocalDateTime theLocalDateTime;
|
||||
|
||||
private LocalDate theLocalDate;
|
||||
|
||||
private LocalTime theLocalTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.javatime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.cfg.MappingSettings;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.jdbc.DateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TimestampJdbcType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
|
||||
|
||||
/**
|
||||
* Tests for "direct" JDBC handling of {@linkplain java.time Java Time} types.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||
@ServiceRegistry(
|
||||
settings = @Setting(name = MappingSettings.PREFER_JAVA_TYPE_JDBC_TYPES, value = "false")
|
||||
)
|
||||
@DomainModel( annotatedClasses = JavaTimeJdbcTypeBaselineTests.EntityWithJavaTimeValues.class )
|
||||
@SessionFactory
|
||||
public class JavaTimeJdbcTypeBaselineTests {
|
||||
@Test
|
||||
void testMappings(DomainModelScope scope) {
|
||||
final PersistentClass entityBinding = scope.getEntityBinding( EntityWithJavaTimeValues.class );
|
||||
|
||||
checkAttribute( entityBinding, "theLocalDate", DateJdbcType.class );
|
||||
checkAttribute( entityBinding, "theLocalDateTime", TimestampJdbcType.class );
|
||||
checkAttribute( entityBinding, "theLocalTime", TimeJdbcType.class );
|
||||
}
|
||||
|
||||
private void checkAttribute(
|
||||
PersistentClass entityBinding,
|
||||
String attributeName,
|
||||
Class<?> expectedJdbcTypeDescriptorType) {
|
||||
final Property property = entityBinding.getProperty( attributeName );
|
||||
final BasicValue value = (BasicValue) property.getValue();
|
||||
final BasicValue.Resolution<?> resolution = value.resolve();
|
||||
final JdbcType jdbcType = resolution.getJdbcType();
|
||||
assertThat( jdbcType ).isInstanceOf( expectedJdbcTypeDescriptorType );
|
||||
}
|
||||
|
||||
@Entity(name="EntityWithJavaTimeValues")
|
||||
@Table(name="EntityWithJavaTimeValues")
|
||||
public static class EntityWithJavaTimeValues {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
private Instant theInstant;
|
||||
|
||||
private LocalDateTime theLocalDateTime;
|
||||
|
||||
private LocalDate theLocalDate;
|
||||
|
||||
private LocalTime theLocalTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.javatime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.cfg.MappingSettings;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.jdbc.DateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JavaTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalDateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalDateTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.LocalTimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TimeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TimestampJdbcType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
|
||||
|
||||
/**
|
||||
* Tests for "direct" JDBC handling of {@linkplain java.time Java Time} types.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||
@ServiceRegistry(
|
||||
settings = @Setting(name = MappingSettings.PREFER_JAVA_TYPE_JDBC_TYPES, value = "false")
|
||||
)
|
||||
@DomainModel( annotatedClasses = JavaTimeJdbcTypeTests.EntityWithJavaTimeValues.class )
|
||||
@SessionFactory
|
||||
@SkipForDialect( dialectClass = SybaseDialect.class, reason = "Sybase drivers do not comply with JDBC 4.2 requirements for support of Java Time objects", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = DB2Dialect.class, reason = "DB2 drivers do not comply with JDBC 4.2 requirements for support of Java Time objects", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = DerbyDialect.class, reason = "Derby drivers do not comply with JDBC 4.2 requirements for support of Java Time objects" )
|
||||
public class JavaTimeJdbcTypeTests {
|
||||
@Test
|
||||
void testMappings(DomainModelScope scope) {
|
||||
final PersistentClass entityBinding = scope.getEntityBinding( EntityWithJavaTimeValues.class );
|
||||
|
||||
checkAttribute( entityBinding, "theLocalDate", LocalDateJdbcType.class );
|
||||
checkAttribute( entityBinding, "theLocalDateTime", LocalDateTimeJdbcType.class );
|
||||
checkAttribute( entityBinding, "theLocalTime", LocalTimeJdbcType.class );
|
||||
}
|
||||
|
||||
private void checkAttribute(
|
||||
PersistentClass entityBinding,
|
||||
String attributeName,
|
||||
Class<?> expectedJdbcTypeDescriptorType) {
|
||||
final Property property = entityBinding.getProperty( attributeName );
|
||||
final BasicValue value = (BasicValue) property.getValue();
|
||||
final BasicValue.Resolution<?> resolution = value.resolve();
|
||||
final JdbcType jdbcType = resolution.getJdbcType();
|
||||
assertThat( jdbcType ).isInstanceOf( expectedJdbcTypeDescriptorType );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInstant(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final Instant start = roundToDefaultPrecision( Instant.EPOCH, dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theInstant = start;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theInstant ).isEqualTo( start );
|
||||
entity.theInstant = start.plus( 2000, ChronoUnit.DAYS );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theInstant ).isEqualTo( start.plus( 2000, ChronoUnit.DAYS ) );
|
||||
entity.theInstant = start.minus( 2000, ChronoUnit.DAYS );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theInstant ).isEqualTo( start.minus( 2000, ChronoUnit.DAYS ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLocalDateTime(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final LocalDateTime start = roundToDefaultPrecision( LocalDateTime.now(), dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theLocalDateTime = start;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDateTime ).isEqualTo( start );
|
||||
entity.theLocalDateTime = start.plusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDateTime ).isEqualTo( start.plusDays( 2000 ) );
|
||||
entity.theLocalDateTime = start.minusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDateTime ).isEqualTo( start.minusDays( 2000 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLocalDate(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final LocalDate startTime = roundToDefaultPrecision( LocalDate.now(), dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theLocalDate = startTime;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDate ).isEqualTo( startTime );
|
||||
entity.theLocalDate = startTime.plusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDate ).isEqualTo( startTime.plusDays( 2000 ) );
|
||||
entity.theLocalDate = startTime.minusDays( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalDate ).isEqualTo( startTime.minusDays( 2000 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect( dialectClass = OracleDialect.class, reason = "Oracle drivers truncate fractional seconds from the LocalTime", matchSubTypes = true)
|
||||
void testLocalTime(SessionFactoryScope scope) {
|
||||
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
|
||||
final LocalTime startTime = roundToDefaultPrecision( LocalTime.now(), dialect );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = new EntityWithJavaTimeValues();
|
||||
entity.id = 1;
|
||||
entity.theLocalTime = startTime;
|
||||
session.persist( entity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalTime ).isEqualTo( startTime );
|
||||
entity.theLocalTime = startTime.plusHours( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalTime ).isEqualTo( startTime.plusHours( 2000 ) );
|
||||
entity.theLocalTime = startTime.plusHours( 2000 );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final EntityWithJavaTimeValues entity = session.get( EntityWithJavaTimeValues.class, 1 );
|
||||
assertThat( entity.theLocalTime ).isEqualTo( startTime.plusHours( 2000 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createMutationQuery( "delete EntityWithJavaTimeValues" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name="EntityWithJavaTimeValues")
|
||||
@Table(name="EntityWithJavaTimeValues")
|
||||
public static class EntityWithJavaTimeValues {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
// @JdbcTypeCode(SqlTypes.INSTANT)
|
||||
private Instant theInstant;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_DATE_TIME)
|
||||
private LocalDateTime theLocalDateTime;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_DATE)
|
||||
private LocalDate theLocalDate;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_TIME)
|
||||
private LocalTime theLocalTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* 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.orm.test.temporal;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.OffsetTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.hibernate.annotations.FractionalSeconds;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.dialect.MariaDBDialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.DateTimeUtils;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||
public class JavaTimeFractionalSecondsTests {
|
||||
@Test
|
||||
@DomainModel(annotatedClasses = {TestEntity.class, TestEntity0.class, TestEntity3.class, TestEntity9.class} )
|
||||
void testMapping(DomainModelScope scope) {
|
||||
final MetadataImplementor domainModel = scope.getDomainModel();
|
||||
|
||||
final Dialect dialect = domainModel.getDatabase().getDialect();
|
||||
final int defaultPrecision = dialect.getDefaultTimestampPrecision();
|
||||
|
||||
final PersistentClass entityBinding = scope.getEntityBinding( TestEntity.class );
|
||||
checkPrecision( "theInstant", defaultPrecision, entityBinding, domainModel );
|
||||
checkPrecision( "theLocalDateTime", defaultPrecision, entityBinding, domainModel );
|
||||
checkPrecision( "theLocalTime", defaultPrecision, entityBinding, domainModel );
|
||||
checkPrecision( "theOffsetDateTime", defaultPrecision, entityBinding, domainModel );
|
||||
checkPrecision( "theOffsetTime", defaultPrecision, entityBinding, domainModel );
|
||||
checkPrecision( "theZonedDateTime", defaultPrecision, entityBinding, domainModel );
|
||||
|
||||
final PersistentClass entityBinding0 = scope.getEntityBinding( TestEntity0.class );
|
||||
checkPrecision( "theInstant", 0, entityBinding0, domainModel );
|
||||
|
||||
final PersistentClass entityBinding3 = scope.getEntityBinding( TestEntity3.class );
|
||||
checkPrecision( "theInstant", 3, entityBinding3, domainModel );
|
||||
checkPrecision( "theLocalDateTime", 3, entityBinding3, domainModel );
|
||||
checkPrecision( "theLocalTime", 3, entityBinding3, domainModel );
|
||||
|
||||
final PersistentClass entityBinding9 = scope.getEntityBinding( TestEntity9.class );
|
||||
checkPrecision( "theInstant", 9, entityBinding9, domainModel );
|
||||
checkPrecision( "theOffsetDateTime", 9, entityBinding9, domainModel );
|
||||
checkPrecision( "theOffsetTime", 9, entityBinding9, domainModel );
|
||||
checkPrecision( "theZonedDateTime", 9, entityBinding9, domainModel );
|
||||
}
|
||||
|
||||
private void checkPrecision(
|
||||
String propertyName,
|
||||
int expectedMinimumSize,
|
||||
PersistentClass entityBinding,
|
||||
MetadataImplementor domainModel) {
|
||||
final Property theInstant = entityBinding.getProperty( propertyName );
|
||||
final BasicValue value = (BasicValue) theInstant.getValue();
|
||||
final Column column = (Column) value.getColumn();
|
||||
final Size columnSize = column.getColumnSize( value.getDialect(), domainModel );
|
||||
assertThat( columnSize.getPrecision() ).isEqualTo( expectedMinimumSize );
|
||||
}
|
||||
|
||||
@Test
|
||||
@DomainModel(annotatedClasses = TestEntity.class)
|
||||
@SessionFactory
|
||||
@SkipForDialect( dialectClass = DB2Dialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
|
||||
void testUsage(SessionFactoryScope scope) {
|
||||
final Instant start = Instant.now();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity testEntity = new TestEntity();
|
||||
testEntity.id = 1;
|
||||
testEntity.theInstant = start;
|
||||
session.persist( testEntity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity testEntity = session.find( TestEntity.class, 1 );
|
||||
|
||||
final Dialect dialect = session.getSessionFactory().getJdbcServices().getDialect();
|
||||
if ( dialect instanceof DerbyDialect
|
||||
|| dialect instanceof MariaDBDialect ) {
|
||||
assertThat( testEntity.theInstant ).isEqualTo( start );
|
||||
}
|
||||
else {
|
||||
assertThat( testEntity.theInstant ).isEqualTo( DateTimeUtils.roundToSecondPrecision( start, 6 ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@DomainModel(annotatedClasses = TestEntity0.class)
|
||||
@SessionFactory
|
||||
@SkipForDialect( dialectClass = H2Dialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = MariaDBDialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = MySQLDialect.class, reason = "Occasional mismatch in rounding versus our code", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = OracleDialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = SQLServerDialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = PostgreSQLDialect.class, reason = "Occasional mismatch in rounding versus our code", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = DerbyDialect.class, reason = "Derby does not support sized timestamp" )
|
||||
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
|
||||
void testUsage0(SessionFactoryScope scope) {
|
||||
final Instant start = Instant.now();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity0 testEntity = new TestEntity0();
|
||||
testEntity.id = 1;
|
||||
testEntity.theInstant = start;
|
||||
session.persist( testEntity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity0 testEntity = session.find( TestEntity0.class, 1 );
|
||||
assertThat( testEntity.theInstant ).isEqualTo( DateTimeUtils.roundToSecondPrecision( start, 0 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@DomainModel(annotatedClasses = TestEntity3.class)
|
||||
@SessionFactory
|
||||
@SkipForDialect( dialectClass = MariaDBDialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = HSQLDialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = DB2Dialect.class, reason = "Occasional mismatch in rounding versus our code" )
|
||||
@SkipForDialect( dialectClass = DerbyDialect.class, reason = "Derby does not support sized timestamp" )
|
||||
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
|
||||
void testUsage3(SessionFactoryScope scope) {
|
||||
final Instant start = Instant.now();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity3 testEntity = new TestEntity3();
|
||||
testEntity.id = 1;
|
||||
testEntity.theInstant = start;
|
||||
session.persist( testEntity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity3 testEntity = session.find( TestEntity3.class, 1 );
|
||||
assertThat( testEntity.theInstant ).isEqualTo( DateTimeUtils.roundToSecondPrecision( start, 3 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@DomainModel(annotatedClasses = TestEntity9.class)
|
||||
@SessionFactory
|
||||
@SkipForDialect( dialectClass = MariaDBDialect.class, reason = "MariaDB only supports precision <= 6" )
|
||||
@SkipForDialect( dialectClass = MySQLDialect.class, reason = "MySQL only supports precision <= 6", matchSubTypes = true )
|
||||
@SkipForDialect( dialectClass = SQLServerDialect.class, reason = "SQL Server only supports precision <= 6" )
|
||||
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
|
||||
void testUsage9(SessionFactoryScope scope) {
|
||||
final Instant start = Instant.now();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity9 testEntity = new TestEntity9();
|
||||
testEntity.id = 1;
|
||||
testEntity.theInstant = start;
|
||||
session.persist( testEntity );
|
||||
} );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final TestEntity9 testEntity = session.find( TestEntity9.class, 1 );
|
||||
|
||||
assertThat( testEntity.theInstant ).isEqualTo( start );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name="TestEntity")
|
||||
@Table(name="TestEntity")
|
||||
public static class TestEntity {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private Instant theInstant;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_DATE_TIME)
|
||||
private LocalDateTime theLocalDateTime;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_TIME)
|
||||
private LocalTime theLocalTime;
|
||||
|
||||
private OffsetDateTime theOffsetDateTime;
|
||||
|
||||
private OffsetTime theOffsetTime;
|
||||
|
||||
private ZonedDateTime theZonedDateTime;
|
||||
|
||||
}
|
||||
|
||||
@Entity(name="TestEntity0")
|
||||
@Table(name="TestEntity0")
|
||||
public static class TestEntity0 {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@FractionalSeconds(0)
|
||||
private Instant theInstant;
|
||||
|
||||
}
|
||||
|
||||
@Entity(name="TestEntity3")
|
||||
@Table(name="TestEntity3")
|
||||
public static class TestEntity3 {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@FractionalSeconds(3)
|
||||
private Instant theInstant;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_DATE_TIME)
|
||||
@FractionalSeconds(3)
|
||||
private LocalDateTime theLocalDateTime;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LOCAL_TIME)
|
||||
@FractionalSeconds(3)
|
||||
private LocalTime theLocalTime;
|
||||
|
||||
}
|
||||
|
||||
@Entity(name="TestEntity9")
|
||||
@Table(name="TestEntity9")
|
||||
public static class TestEntity9 {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@FractionalSeconds(9)
|
||||
private Instant theInstant;
|
||||
|
||||
@FractionalSeconds(9)
|
||||
private OffsetDateTime theOffsetDateTime;
|
||||
|
||||
@FractionalSeconds(9)
|
||||
private OffsetTime theOffsetTime;
|
||||
|
||||
@FractionalSeconds(9)
|
||||
private ZonedDateTime theZonedDateTime;
|
||||
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
:versionDocBase: {docsBase}/6.5
|
||||
:userGuideBase: {versionDocBase}/userguide/html_single/Hibernate_User_Guide.html
|
||||
:javadocsBase: {versionDocBase}/javadocs
|
||||
|
||||
:fn-instant: footnote:instant[JDBC 4.2, curiously, does not define support for Instant to be directly marshalled through the driver.]
|
||||
|
||||
This guide discusses migration to Hibernate ORM version 6.5. For migration from
|
||||
earlier versions, see any other pertinent migration guides as well.
|
||||
|
@ -16,3 +16,26 @@ earlier versions, see any other pertinent migration guides as well.
|
|||
* link:{docsBase}/6.1/migration-guide/migration-guide.html[6.1 Migration guide]
|
||||
* link:{docsBase}/6.0/migration-guide/migration-guide.html[6.0 Migration guide]
|
||||
|
||||
|
||||
[[java-time]]
|
||||
== Java Time Handling
|
||||
|
||||
6.5 adds support for marshalling Java Time objects directly through the JDBC driver as defined by JDBC 4.2.
|
||||
In previous versions, Hibernate would handle Java Time objects using `java.sql.Date`, `java.sql.Time` or
|
||||
`java.sql.Timestamp` references as intermediate forms.
|
||||
|
||||
Another behavioral change with this is handling for timezones. `OffsetDateTime`, `OffsetTime` and
|
||||
`ZonedDateTime` all encode explicit timezone information. With direct marshalling, Hibernate simply
|
||||
passes along the value as-is. In the legacy behavior, since the `java.sql` variants do not
|
||||
encode timezone information, Hibernate generally has to specially handle timezones when converting to
|
||||
those intermediate forms.
|
||||
|
||||
For 6.5 this behavior is disabled by default. To opt-in,
|
||||
|
||||
[source]
|
||||
----
|
||||
hibernate.type.prefer_java_type_jdbc_types=false
|
||||
----
|
||||
|
||||
It is expected the default will flip for 7.0.
|
||||
|
||||
|
|
|
@ -393,6 +393,11 @@ public abstract class MockSessionFactory
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreferJavaTimeJdbcTypesEnabled() {
|
||||
return MetadataBuildingContext.super.isPreferJavaTimeJdbcTypesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastSessionServices getFastSessionServices() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
Loading…
Reference in New Issue