Support for type coercion for values passed as ids and as query parameter bindings
- widening coercions - valid (no over/under flow) narrowing coercions
This commit is contained in:
parent
27662f91a9
commit
d95806b516
|
@ -35,6 +35,8 @@ import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
|
||||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder.Options;
|
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder.Options;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the internal contract shared between {@link org.hibernate.Session} and
|
* Defines the internal contract shared between {@link org.hibernate.Session} and
|
||||||
|
@ -66,7 +68,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface SharedSessionContractImplementor
|
public interface SharedSessionContractImplementor
|
||||||
extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions, QueryProducerImplementor {
|
extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions, QueryProducerImplementor, JavaTypeDescriptor.CoercionContext {
|
||||||
|
|
||||||
// todo : this is the shared contract between Session and StatelessSession, but it defines methods that StatelessSession does not implement
|
// todo : this is the shared contract between Session and StatelessSession, but it defines methods that StatelessSession does not implement
|
||||||
// (it just throws UnsupportedOperationException). To me it seems like it is better to properly isolate those methods
|
// (it just throws UnsupportedOperationException). To me it seems like it is better to properly isolate those methods
|
||||||
|
@ -82,6 +84,11 @@ public interface SharedSessionContractImplementor
|
||||||
*/
|
*/
|
||||||
SessionFactoryImplementor getFactory();
|
SessionFactoryImplementor getFactory();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default TypeConfiguration getTypeConfiguration() {
|
||||||
|
return getFactory().getTypeConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
SessionEventListenerManager getEventListenerManager();
|
SessionEventListenerManager getEventListenerManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,11 +27,13 @@ import org.hibernate.graph.spi.RootGraphImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
|
public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, JavaTypeDescriptor.CoercionContext {
|
||||||
private final LoadAccessContext context;
|
private final LoadAccessContext context;
|
||||||
private final EntityPersister entityPersister;
|
private final EntityPersister entityPersister;
|
||||||
|
|
||||||
|
@ -114,6 +116,8 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
|
||||||
final EventSource eventSource = (EventSource) session;
|
final EventSource eventSource = (EventSource) session;
|
||||||
final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
|
final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
|
||||||
|
|
||||||
|
id = entityPersister.getIdentifierMapping().getJavaTypeDescriptor().coerce( id, this );
|
||||||
|
|
||||||
if ( this.lockOptions != null ) {
|
if ( this.lockOptions != null ) {
|
||||||
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, eventSource, loadQueryInfluencers.getReadOnly() );
|
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, eventSource, loadQueryInfluencers.getReadOnly() );
|
||||||
context.fireLoad( event, LoadEventListener.LOAD );
|
context.fireLoad( event, LoadEventListener.LOAD );
|
||||||
|
@ -154,6 +158,8 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
|
||||||
final EventSource eventSource = (EventSource) session;
|
final EventSource eventSource = (EventSource) session;
|
||||||
final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
|
final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
|
||||||
|
|
||||||
|
id = entityPersister.getIdentifierMapping().getJavaTypeDescriptor().coerce( id, this );
|
||||||
|
|
||||||
if ( this.lockOptions != null ) {
|
if ( this.lockOptions != null ) {
|
||||||
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, eventSource, loadQueryInfluencers.getReadOnly() );
|
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, eventSource, loadQueryInfluencers.getReadOnly() );
|
||||||
context.fireLoad( event, LoadEventListener.GET );
|
context.fireLoad( event, LoadEventListener.GET );
|
||||||
|
@ -206,4 +212,9 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
|
||||||
( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( result, null );
|
( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( result, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeConfiguration getTypeConfiguration() {
|
||||||
|
return context.getSession().getSessionFactory().getTypeConfiguration();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
|
||||||
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
|
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
|
||||||
|
|
||||||
for ( int i = 0; i < ids.length; i++ ) {
|
for ( int i = 0; i < ids.length; i++ ) {
|
||||||
final Object id = ids[i];
|
final Object id = entityDescriptor.getIdentifierMapping().getJavaTypeDescriptor().coerce( ids[i], session );
|
||||||
final EntityKey entityKey = new EntityKey( id, entityDescriptor );
|
final EntityKey entityKey = new EntityKey( id, entityDescriptor );
|
||||||
|
|
||||||
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
||||||
|
@ -175,7 +175,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
|
||||||
|
|
||||||
// if we did not hit any of the continues above, then we need to batch
|
// if we did not hit any of the continues above, then we need to batch
|
||||||
// load the entity state.
|
// load the entity state.
|
||||||
idsInBatch.add( ids[i] );
|
idsInBatch.add( id );
|
||||||
|
|
||||||
if ( idsInBatch.size() >= maxBatchSize ) {
|
if ( idsInBatch.size() >= maxBatchSize ) {
|
||||||
// we've hit the allotted max-batch-size, perform an "intermediate load"
|
// we've hit the allotted max-batch-size, perform an "intermediate load"
|
||||||
|
@ -352,7 +352,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
|
||||||
final List<Object> nonManagedIds = new ArrayList<>();
|
final List<Object> nonManagedIds = new ArrayList<>();
|
||||||
|
|
||||||
for ( int i = 0; i < ids.length; i++ ) {
|
for ( int i = 0; i < ids.length; i++ ) {
|
||||||
final Object id = ids[ i ];
|
final Object id = entityDescriptor.getIdentifierMapping().getJavaTypeDescriptor().coerce( ids[ i ], session );
|
||||||
final EntityKey entityKey = new EntityKey( id, entityDescriptor );
|
final EntityKey entityKey = new EntityKey( id, entityDescriptor );
|
||||||
|
|
||||||
LoadEvent loadEvent = new LoadEvent(
|
LoadEvent loadEvent = new LoadEvent(
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
@ -32,12 +33,14 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single-attribute NaturalIdMapping implementation
|
* Single-attribute NaturalIdMapping implementation
|
||||||
*/
|
*/
|
||||||
public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements JavaTypeDescriptor.CoercionContext {
|
||||||
private final SingularAttributeMapping attribute;
|
private final SingularAttributeMapping attribute;
|
||||||
|
private final TypeConfiguration typeConfiguration;
|
||||||
|
|
||||||
public SimpleNaturalIdMapping(
|
public SimpleNaturalIdMapping(
|
||||||
SingularAttributeMapping attribute,
|
SingularAttributeMapping attribute,
|
||||||
|
@ -48,6 +51,11 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
||||||
attribute.getAttributeMetadataAccess().resolveAttributeMetadata( declaringType ).isUpdatable()
|
attribute.getAttributeMetadataAccess().resolveAttributeMetadata( declaringType ).isUpdatable()
|
||||||
);
|
);
|
||||||
this.attribute = attribute;
|
this.attribute = attribute;
|
||||||
|
|
||||||
|
typeConfiguration = creationProcess.getCreationContext()
|
||||||
|
.getSessionFactory()
|
||||||
|
.getTypeConfiguration();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,15 +120,21 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
||||||
|
|
||||||
if ( ! getJavaTypeDescriptor().getJavaTypeClass().isInstance( naturalIdValue ) ) {
|
if ( ! getJavaTypeDescriptor().getJavaTypeClass().isInstance( naturalIdValue ) ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Incoming natural-id value [" + naturalIdValue + "] is not of expected type ["
|
String.format(
|
||||||
+ getJavaTypeDescriptor().getJavaType().getTypeName() + "]"
|
Locale.ROOT,
|
||||||
|
"Incoming natural-id value [%s (`%s`)] is not of expected type [`%s`] and could not be coerced",
|
||||||
|
naturalIdValue,
|
||||||
|
naturalIdValue.getClass().getName(),
|
||||||
|
getJavaTypeDescriptor().getJavaType().getTypeName()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculateHashCode(Object value, SharedSessionContractImplementor session) {
|
public int calculateHashCode(Object value, SharedSessionContractImplementor session) {
|
||||||
return 0;
|
//noinspection unchecked
|
||||||
|
return value == null ? 0 : ( (JavaTypeDescriptor<Object>) getJavaTypeDescriptor() ).extractHashCode( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -134,16 +148,16 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
||||||
final Map valueMap = (Map) naturalIdToLoad;
|
final Map valueMap = (Map) naturalIdToLoad;
|
||||||
assert valueMap.size() == 1;
|
assert valueMap.size() == 1;
|
||||||
assert valueMap.containsKey( getAttribute().getAttributeName() );
|
assert valueMap.containsKey( getAttribute().getAttributeName() );
|
||||||
return valueMap.get( getAttribute().getAttributeName() );
|
return getJavaTypeDescriptor().coerce( valueMap.get( getAttribute().getAttributeName() ), this );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( naturalIdToLoad instanceof Object[] ) {
|
if ( naturalIdToLoad instanceof Object[] ) {
|
||||||
final Object[] values = (Object[]) naturalIdToLoad;
|
final Object[] values = (Object[]) naturalIdToLoad;
|
||||||
assert values.length == 1;
|
assert values.length == 1;
|
||||||
return values[0];
|
return getJavaTypeDescriptor().coerce( values[0], this );
|
||||||
}
|
}
|
||||||
|
|
||||||
return naturalIdToLoad;
|
return getJavaTypeDescriptor().coerce( naturalIdToLoad, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
public SingularAttributeMapping getAttribute() {
|
public SingularAttributeMapping getAttribute() {
|
||||||
|
@ -247,4 +261,9 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
||||||
public MultiNaturalIdLoader<?> makeMultiLoader(EntityMappingType entityDescriptor) {
|
public MultiNaturalIdLoader<?> makeMultiLoader(EntityMappingType entityDescriptor) {
|
||||||
return new MultiNaturalIdLoaderStandard<>( entityDescriptor );
|
return new MultiNaturalIdLoaderStandard<>( entityDescriptor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeConfiguration getTypeConfiguration() {
|
||||||
|
return typeConfiguration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
|
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
|
||||||
import org.hibernate.query.spi.QueryParameterBindingValidator;
|
import org.hibernate.query.spi.QueryParameterBindingValidator;
|
||||||
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +28,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, JavaTypeDescriptor.CoercionContext {
|
||||||
private final QueryParameter<T> queryParameter;
|
private final QueryParameter<T> queryParameter;
|
||||||
private final QueryParameterBindingTypeResolver typeResolver;
|
private final QueryParameterBindingTypeResolver typeResolver;
|
||||||
private final boolean isBindingValidationRequired;
|
private final boolean isBindingValidationRequired;
|
||||||
|
@ -103,6 +105,13 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( bindType != null ) {
|
||||||
|
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||||
|
}
|
||||||
|
else if ( queryParameter.getHibernateType() != null ) {
|
||||||
|
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||||
|
}
|
||||||
|
|
||||||
if ( isBindingValidationRequired ) {
|
if ( isBindingValidationRequired ) {
|
||||||
validate( value );
|
validate( value );
|
||||||
}
|
}
|
||||||
|
@ -148,15 +157,22 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( clarifiedType != null ) {
|
||||||
|
this.bindType = clarifiedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bindType != null ) {
|
||||||
|
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||||
|
}
|
||||||
|
else if ( queryParameter.getHibernateType() != null ) {
|
||||||
|
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||||
|
}
|
||||||
|
|
||||||
if ( isBindingValidationRequired ) {
|
if ( isBindingValidationRequired ) {
|
||||||
validate( value, clarifiedType );
|
validate( value, clarifiedType );
|
||||||
}
|
}
|
||||||
|
|
||||||
bindValue( value );
|
bindValue( value );
|
||||||
|
|
||||||
if ( clarifiedType != null ) {
|
|
||||||
this.bindType = clarifiedType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -165,16 +181,23 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( bindType == null ) {
|
||||||
|
bindType = queryParameter.getHibernateType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bindType != null ) {
|
||||||
|
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||||
|
}
|
||||||
|
else if ( queryParameter.getHibernateType() != null ) {
|
||||||
|
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );
|
||||||
|
}
|
||||||
|
|
||||||
if ( isBindingValidationRequired ) {
|
if ( isBindingValidationRequired ) {
|
||||||
validate( value, temporalTypePrecision );
|
validate( value, temporalTypePrecision );
|
||||||
}
|
}
|
||||||
|
|
||||||
bindValue( value );
|
bindValue( value );
|
||||||
|
|
||||||
if ( bindType == null ) {
|
|
||||||
bindType = queryParameter.getHibernateType();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( bindType != null ) {
|
if ( bindType != null ) {
|
||||||
bindType = (AllowableParameterType) BindingTypeHelper.INSTANCE.resolveDateTemporalTypeVariant(
|
bindType = (AllowableParameterType) BindingTypeHelper.INSTANCE.resolveDateTemporalTypeVariant(
|
||||||
bindType.getExpressableJavaTypeDescriptor().getJavaTypeClass(),
|
bindType.getExpressableJavaTypeDescriptor().getJavaTypeClass(),
|
||||||
|
@ -221,10 +244,10 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBindValues(Collection<T> values, AllowableParameterType<T> clarifiedType) {
|
public void setBindValues(Collection<T> values, AllowableParameterType<T> clarifiedType) {
|
||||||
setBindValues( values );
|
|
||||||
if ( clarifiedType != null ) {
|
if ( clarifiedType != null ) {
|
||||||
this.bindType = clarifiedType;
|
this.bindType = clarifiedType;
|
||||||
}
|
}
|
||||||
|
setBindValues( values );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -237,7 +260,7 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
||||||
this.bindType = BindingTypeHelper.INSTANCE.resolveTemporalPrecision(
|
this.bindType = BindingTypeHelper.INSTANCE.resolveTemporalPrecision(
|
||||||
temporalTypePrecision,
|
temporalTypePrecision,
|
||||||
bindType,
|
bindType,
|
||||||
typeConfiguration
|
getTypeConfiguration()
|
||||||
);
|
);
|
||||||
|
|
||||||
this.explicitTemporalPrecision = temporalTypePrecision;
|
this.explicitTemporalPrecision = temporalTypePrecision;
|
||||||
|
@ -273,4 +296,9 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T> {
|
||||||
private void validate(T value, TemporalType clarifiedTemporalType) {
|
private void validate(T value, TemporalType clarifiedTemporalType) {
|
||||||
QueryParameterBindingValidator.INSTANCE.validate( getBindType(), value, clarifiedTemporalType );
|
QueryParameterBindingValidator.INSTANCE.validate( getBindType(), value, clarifiedTemporalType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeConfiguration getTypeConfiguration() {
|
||||||
|
return typeResolver.getTypeConfiguration();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
|
||||||
import org.hibernate.property.access.spi.Getter;
|
import org.hibernate.property.access.spi.Getter;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.query.IllegalQueryOperationException;
|
import org.hibernate.query.IllegalQueryOperationException;
|
||||||
import org.hibernate.query.ParameterMetadata;
|
|
||||||
import org.hibernate.query.QueryLogging;
|
import org.hibernate.query.QueryLogging;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.ResultListTransformer;
|
import org.hibernate.query.ResultListTransformer;
|
||||||
|
|
|
@ -54,7 +54,6 @@ public interface QueryParameterBinding<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the parameter binding value using the explicit Type.
|
* Sets the parameter binding value using the explicit Type.
|
||||||
*
|
|
||||||
* @param value The bind value
|
* @param value The bind value
|
||||||
* @param clarifiedType The explicit Type to use
|
* @param clarifiedType The explicit Type to use
|
||||||
*/
|
*/
|
||||||
|
@ -62,7 +61,6 @@ public interface QueryParameterBinding<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the parameter binding value using the explicit TemporalType.
|
* Sets the parameter binding value using the explicit TemporalType.
|
||||||
*
|
|
||||||
* @param value The bind value
|
* @param value The bind value
|
||||||
* @param temporalTypePrecision The temporal type to use
|
* @param temporalTypePrecision The temporal type to use
|
||||||
*/
|
*/
|
||||||
|
@ -78,14 +76,13 @@ public interface QueryParameterBinding<T> {
|
||||||
/**
|
/**
|
||||||
* Sets the parameter binding values. The inherent parameter type (if known) is assumed in regards to the
|
* Sets the parameter binding values. The inherent parameter type (if known) is assumed in regards to the
|
||||||
* individual values.
|
* individual values.
|
||||||
|
* @param values The bind values
|
||||||
*
|
*
|
||||||
* @param values The bind values
|
|
||||||
*/
|
*/
|
||||||
void setBindValues(Collection<T> values);
|
void setBindValues(Collection<T> values);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the parameter binding values using the explicit Type in regards to the individual values.
|
* Sets the parameter binding values using the explicit Type in regards to the individual values.
|
||||||
*
|
|
||||||
* @param values The bind values
|
* @param values The bind values
|
||||||
* @param clarifiedType The explicit Type to use
|
* @param clarifiedType The explicit Type to use
|
||||||
*/
|
*/
|
||||||
|
@ -93,8 +90,7 @@ public interface QueryParameterBinding<T> {
|
||||||
|
|
||||||
/**Sets the parameter binding value using the explicit TemporalType in regards to the individual values.
|
/**Sets the parameter binding value using the explicit TemporalType in regards to the individual values.
|
||||||
*
|
*
|
||||||
*
|
* @param values The bind values
|
||||||
* @param values The bind values
|
|
||||||
* @param temporalTypePrecision The temporal type to use
|
* @param temporalTypePrecision The temporal type to use
|
||||||
*/
|
*/
|
||||||
void setBindValues(Collection<T> values, TemporalType temporalTypePrecision, TypeConfiguration typeConfiguration);
|
void setBindValues(Collection<T> values, TemporalType temporalTypePrecision, TypeConfiguration typeConfiguration);
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
@ -78,13 +79,13 @@ public class BigDecimalTypeDescriptor extends AbstractClassTypeDescriptor<BigDec
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( BigDecimal.class.isInstance( value ) ) {
|
if ( value instanceof BigDecimal ) {
|
||||||
return (BigDecimal) value;
|
return (BigDecimal) value;
|
||||||
}
|
}
|
||||||
if ( BigInteger.class.isInstance( value ) ) {
|
if ( value instanceof BigInteger ) {
|
||||||
return new BigDecimal( (BigInteger) value );
|
return new BigDecimal( (BigInteger) value );
|
||||||
}
|
}
|
||||||
if ( Number.class.isInstance( value ) ) {
|
if ( value instanceof Number ) {
|
||||||
return BigDecimal.valueOf( ( (Number) value ).doubleValue() );
|
return BigDecimal.valueOf( ( (Number) value ).doubleValue() );
|
||||||
}
|
}
|
||||||
throw unknownWrap( value.getClass() );
|
throw unknownWrap( value.getClass() );
|
||||||
|
@ -99,4 +100,30 @@ public class BigDecimalTypeDescriptor extends AbstractClassTypeDescriptor<BigDec
|
||||||
public int getDefaultSqlPrecision(Dialect dialect) {
|
public int getDefaultSqlPrecision(Dialect dialect) {
|
||||||
return dialect.getDefaultDecimalPrecision();
|
return dialect.getDefaultDecimalPrecision();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> BigDecimal coerce(X value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Number ) {
|
||||||
|
return BigDecimal.valueOf( ( (Number) value ).doubleValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> BigDecimal.valueOf( Double.parseDouble( (String) value ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce value [%s (%s)] to BigDecimal",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
@ -82,13 +83,13 @@ public class BigIntegerTypeDescriptor extends AbstractClassTypeDescriptor<BigInt
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( BigInteger.class.isInstance( value ) ) {
|
if ( value instanceof BigInteger ) {
|
||||||
return (BigInteger) value;
|
return (BigInteger) value;
|
||||||
}
|
}
|
||||||
if ( BigDecimal.class.isInstance( value ) ) {
|
if ( value instanceof BigDecimal ) {
|
||||||
return ( (BigDecimal) value ).toBigIntegerExact();
|
return ( (BigDecimal) value ).toBigIntegerExact();
|
||||||
}
|
}
|
||||||
if ( Number.class.isInstance( value ) ) {
|
if ( value instanceof Number ) {
|
||||||
return BigInteger.valueOf( ( (Number) value ).longValue() );
|
return BigInteger.valueOf( ( (Number) value ).longValue() );
|
||||||
}
|
}
|
||||||
throw unknownWrap( value.getClass() );
|
throw unknownWrap( value.getClass() );
|
||||||
|
@ -108,4 +109,58 @@ public class BigIntegerTypeDescriptor extends AbstractClassTypeDescriptor<BigInt
|
||||||
public int getDefaultSqlScale() {
|
public int getDefaultSqlScale() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> BigInteger coerce(X value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return (BigInteger) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return BigInteger.valueOf( ( (byte) value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return BigInteger.valueOf( ( (short) value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return BigInteger.valueOf( ( (int) value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return BigInteger.valueOf( ( (long) value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return CoercionHelper.toBigInteger( (Double) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return CoercionHelper.toBigInteger( (Float) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return CoercionHelper.toBigInteger( (BigDecimal) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> BigInteger.valueOf( Long.parseLong( (String) value ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce value [%s (%s)] to BigInteger",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type.descriptor.java;
|
package org.hibernate.type.descriptor.java;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.java.spi.Primitive;
|
import org.hibernate.type.descriptor.java.spi.Primitive;
|
||||||
|
@ -66,20 +70,20 @@ public class ByteTypeDescriptor extends AbstractClassTypeDescriptor<Byte> implem
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Byte.class.isInstance( value ) ) {
|
if ( value instanceof Byte ) {
|
||||||
return (Byte) value;
|
return (Byte) value;
|
||||||
}
|
}
|
||||||
if ( Number.class.isInstance( value ) ) {
|
if ( value instanceof Number ) {
|
||||||
return ( (Number) value ).byteValue();
|
return ( (Number) value ).byteValue();
|
||||||
}
|
}
|
||||||
if ( String.class.isInstance( value ) ) {
|
if ( value instanceof String ) {
|
||||||
return Byte.valueOf( ( (String) value ) );
|
return Byte.valueOf( ( (String) value ) );
|
||||||
}
|
}
|
||||||
throw unknownWrap( value.getClass() );
|
throw unknownWrap( value.getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class getPrimitiveClass() {
|
public Class<Byte> getPrimitiveClass() {
|
||||||
return byte.class;
|
return byte.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,4 +106,58 @@ public class ByteTypeDescriptor extends AbstractClassTypeDescriptor<Byte> implem
|
||||||
public int getDefaultSqlScale() {
|
public int getDefaultSqlScale() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> Byte coerce(X value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return (byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return CoercionHelper.toByte( (short) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return CoercionHelper.toByte( (Integer) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return CoercionHelper.toByte( (Long) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return CoercionHelper.toByte( (Double) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return CoercionHelper.toByte( (Float) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return CoercionHelper.toByte( (BigInteger) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return CoercionHelper.toByte( (BigDecimal) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> Byte.parseByte( (String) value )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce value `%s` [%s] as Byte",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class CoercionException extends HibernateException {
|
||||||
|
public CoercionException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoercionException(String message, Throwable cause) {
|
||||||
|
super( message, cause );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,399 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for type coercions. Mainly used for narrowing coercions which
|
||||||
|
* might lead to under/over-flow problems
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class CoercionHelper {
|
||||||
|
private CoercionHelper() {
|
||||||
|
// disallow direct instantiation
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(Short value) {
|
||||||
|
if ( value > Byte.MAX_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Short value `%s` to Byte : overflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Byte.MIN_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Short value `%s` to Byte : underflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(Integer value) {
|
||||||
|
if ( value > Byte.MAX_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Integer value `%s` to Byte : overflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Byte.MIN_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Integer value `%s` to Byte : underflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(Long value) {
|
||||||
|
if ( value > Byte.MAX_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Long value `%s` to Byte : overflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Byte.MIN_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Long value `%s` to Byte : underflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(Double value) {
|
||||||
|
if ( ! isWholeNumber( value ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Double value `%s` to Byte : not a whole number",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value > Byte.MAX_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Double value `%s` to Byte : overflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Byte.MIN_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Double value `%s` to Byte : underflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(Float value) {
|
||||||
|
if ( ! isWholeNumber( value ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Float value `%s` to Byte : not a whole number",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value > Byte.MAX_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Float value `%s` to Byte : overflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Byte.MIN_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Float value `%s` to Byte : underflow",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(BigInteger value) {
|
||||||
|
return coerceWrappingError( value::byteValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Byte toByte(BigDecimal value) {
|
||||||
|
return coerceWrappingError( value::byteValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(Byte value) {
|
||||||
|
return value.shortValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(Integer value) {
|
||||||
|
if ( value > Short.MAX_VALUE ) {
|
||||||
|
throw new CoercionException( "Cannot coerce Integer value `" + value + "` as Short : overflow" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Short.MIN_VALUE ) {
|
||||||
|
throw new CoercionException( "Cannot coerce Integer value `" + value + "` as Short : underflow" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.shortValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(Long value) {
|
||||||
|
if ( value > Short.MAX_VALUE ) {
|
||||||
|
throw new CoercionException( "Cannot coerce Long value `" + value + "` as Short : overflow" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value < Short.MIN_VALUE ) {
|
||||||
|
throw new CoercionException( "Cannot coerce Long value `" + value + "` as Short : underflow" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.shortValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(Double doubleValue) {
|
||||||
|
if ( ! isWholeNumber( doubleValue ) ) {
|
||||||
|
throw new CoercionException( "Cannot coerce Double value `" + doubleValue + "` as Short : not a whole number" );
|
||||||
|
}
|
||||||
|
return toShort( doubleValue.longValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(Float floatValue) {
|
||||||
|
if ( ! isWholeNumber( floatValue ) ) {
|
||||||
|
throw new CoercionException( "Cannot coerce Float value `" + floatValue + "` as Short : not a whole number" );
|
||||||
|
}
|
||||||
|
return toShort( floatValue.longValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(BigInteger value) {
|
||||||
|
return coerceWrappingError( value::shortValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Short toShort(BigDecimal value) {
|
||||||
|
return coerceWrappingError( value::shortValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(Byte value) {
|
||||||
|
return value.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(Short value) {
|
||||||
|
return value.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(Long value) {
|
||||||
|
return coerceWrappingError( () -> Math.toIntExact( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(Double doubleValue) {
|
||||||
|
if ( ! isWholeNumber( doubleValue ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce Double value `%s` to Integer: not a whole number",
|
||||||
|
doubleValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return toInteger( doubleValue.longValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(Float floatValue) {
|
||||||
|
if ( ! isWholeNumber( floatValue ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce Float value `%s` to Integer: not a whole number",
|
||||||
|
floatValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return toInteger( floatValue.longValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(BigInteger value) {
|
||||||
|
return coerceWrappingError( value::intValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer toInteger(BigDecimal value) {
|
||||||
|
return coerceWrappingError( value::intValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(Byte value) {
|
||||||
|
return value.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(Short value) {
|
||||||
|
return value.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(Integer value) {
|
||||||
|
return value.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(Double doubleValue) {
|
||||||
|
if ( ! isWholeNumber( doubleValue ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce Double value `%s` as Integer: not a whole number",
|
||||||
|
doubleValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return doubleValue.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(Float floatValue) {
|
||||||
|
if ( ! isWholeNumber( floatValue ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce Float value `%s` as Integer: not a whole number",
|
||||||
|
floatValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return floatValue.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(BigInteger value) {
|
||||||
|
return coerceWrappingError( value::longValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long toLong(BigDecimal value) {
|
||||||
|
return coerceWrappingError( value::longValueExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BigInteger toBigInteger(Double doubleValue) {
|
||||||
|
if ( ! isWholeNumber( doubleValue ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce Double value `%s` as BigInteger: not a whole number",
|
||||||
|
doubleValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return BigInteger.valueOf( doubleValue.longValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BigInteger toBigInteger(Float floatValue) {
|
||||||
|
if ( ! isWholeNumber( floatValue ) ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Unable to coerce Double Float `%s` as BigInteger: not a whole number",
|
||||||
|
floatValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return BigInteger.valueOf( floatValue.longValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BigInteger toBigInteger(BigDecimal value) {
|
||||||
|
return coerceWrappingError( value::toBigIntegerExact );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double toDouble(Float floatValue) {
|
||||||
|
if ( floatValue > (float) Double.MAX_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Float value `%s` to Double : overflow",
|
||||||
|
floatValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( floatValue < (float) Double.MIN_VALUE ) {
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce Float value `%s` to Double : underflow",
|
||||||
|
floatValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double) floatValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double toDouble(BigInteger value) {
|
||||||
|
return coerceWrappingError( value::doubleValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double toDouble(BigDecimal value) {
|
||||||
|
return coerceWrappingError( value::doubleValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWholeNumber(double doubleValue) {
|
||||||
|
return doubleValue % 1 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWholeNumber(float floatValue) {
|
||||||
|
return floatValue == ( (float) (long) floatValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Coercer<T> {
|
||||||
|
T doCoercion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T coerceWrappingError(Coercer<T> coercer) {
|
||||||
|
try {
|
||||||
|
return coercer.doCoercion();
|
||||||
|
}
|
||||||
|
catch (ArithmeticException | NumberFormatException e) {
|
||||||
|
throw new CoercionException( "Error coercing value", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ package org.hibernate.type.descriptor.java;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
@ -121,4 +122,58 @@ public class DoubleTypeDescriptor extends AbstractClassTypeDescriptor<Double> im
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> Double coerce(X value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return ( (Double) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return ( (Byte) value ).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return ( (Short) value ).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return ( (Integer) value ).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return ( (Long) value ).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return CoercionHelper.toDouble( (float) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return CoercionHelper.toDouble( (BigInteger) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return CoercionHelper.toDouble( (BigDecimal) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> Double.parseDouble( (String) value )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce value `%s` [%s] as Double",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
@ -109,4 +110,58 @@ public class FloatTypeDescriptor extends AbstractClassTypeDescriptor<Float> impl
|
||||||
//in a single-precision FP number
|
//in a single-precision FP number
|
||||||
return dialect.getFloatPrecision();
|
return dialect.getFloatPrecision();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> Float coerce(X value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return (Float) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return ( (Double) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return ( (Byte) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return ( (Short) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return ( (Integer) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return ( (Long) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return ( (BigInteger) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return ( (BigDecimal) value ).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> Float.parseFloat( (String) value )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce value `%s` [%s] as Float",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
@ -110,4 +111,58 @@ public class IntegerTypeDescriptor extends AbstractClassTypeDescriptor<Integer>
|
||||||
public int getDefaultSqlScale() {
|
public int getDefaultSqlScale() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer coerce(Object value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return (int) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return CoercionHelper.toInteger( (short) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return CoercionHelper.toInteger( (byte) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return CoercionHelper.toInteger( (long) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return CoercionHelper.toInteger( (double) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return CoercionHelper.toInteger( (float) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return CoercionHelper.toInteger( (BigInteger) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return CoercionHelper.toInteger( (BigDecimal) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> Integer.parseInt( (String) value )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce vale `%s` [%s] as Integer",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.internal.util.compare.ComparableComparator;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
|
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
|
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptor for the Java side of a value mapping.
|
* Descriptor for the Java side of a value mapping.
|
||||||
|
@ -179,6 +180,15 @@ public interface JavaTypeDescriptor<T> extends Serializable {
|
||||||
*/
|
*/
|
||||||
<X> T wrap(X value, WrapperOptions options);
|
<X> T wrap(X value, WrapperOptions options);
|
||||||
|
|
||||||
|
interface CoercionContext {
|
||||||
|
TypeConfiguration getTypeConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
default <X> T coerce(X value, CoercionContext coercionContext) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the Java type handled here.
|
* Retrieve the Java type handled here.
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
@ -74,18 +75,72 @@ public class LongTypeDescriptor extends AbstractClassTypeDescriptor<Long> implem
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Long.class.isInstance( value ) ) {
|
if ( value instanceof Long ) {
|
||||||
return (Long) value;
|
return (Long) value;
|
||||||
}
|
}
|
||||||
if ( Number.class.isInstance( value ) ) {
|
if ( value instanceof Number ) {
|
||||||
return ( (Number) value ).longValue();
|
return ( (Number) value ).longValue();
|
||||||
}
|
}
|
||||||
else if ( String.class.isInstance( value ) ) {
|
else if ( value instanceof String ) {
|
||||||
return Long.valueOf( ( (String) value ) );
|
return Long.valueOf( ( (String) value ) );
|
||||||
}
|
}
|
||||||
throw unknownWrap( value.getClass() );
|
throw unknownWrap( value.getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> Long coerce(X value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return ( (Long) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return CoercionHelper.toLong( (Byte) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return CoercionHelper.toLong( (Short) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return CoercionHelper.toLong( (Integer) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return CoercionHelper.toLong( (Double) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return CoercionHelper.toLong( (Float) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return CoercionHelper.toLong( (BigInteger) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return CoercionHelper.toLong( (BigDecimal) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> Long.parseLong( (String) value )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce value `%s` [%s] as Long",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class getPrimitiveClass() {
|
public Class getPrimitiveClass() {
|
||||||
return long.class;
|
return long.class;
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type.descriptor.java;
|
package org.hibernate.type.descriptor.java;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.java.spi.Primitive;
|
import org.hibernate.type.descriptor.java.spi.Primitive;
|
||||||
|
@ -76,7 +80,7 @@ public class ShortTypeDescriptor extends AbstractClassTypeDescriptor<Short> impl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class getPrimitiveClass() {
|
public Class<Short> getPrimitiveClass() {
|
||||||
return short.class;
|
return short.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,4 +103,58 @@ public class ShortTypeDescriptor extends AbstractClassTypeDescriptor<Short> impl
|
||||||
public int getDefaultSqlScale() {
|
public int getDefaultSqlScale() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Short coerce(Object value, CoercionContext coercionContext) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Short ) {
|
||||||
|
return (short) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Byte ) {
|
||||||
|
return CoercionHelper.toShort( (Byte) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Integer ) {
|
||||||
|
return CoercionHelper.toShort( (Integer) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Long ) {
|
||||||
|
return CoercionHelper.toShort( (Long) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Double ) {
|
||||||
|
return CoercionHelper.toShort( (Double) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Float ) {
|
||||||
|
return CoercionHelper.toShort( (Float) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigInteger ) {
|
||||||
|
return CoercionHelper.toShort( (BigInteger) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof BigDecimal ) {
|
||||||
|
return CoercionHelper.toShort( (BigDecimal) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof String ) {
|
||||||
|
return CoercionHelper.coerceWrappingError(
|
||||||
|
() -> Short.parseShort( (String) value )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CoercionException(
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"Cannot coerce value `%s` [%s] as Short",
|
||||||
|
value,
|
||||||
|
value.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,313 @@
|
||||||
|
/*
|
||||||
|
* 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.type.java;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.NaturalId;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.query.spi.QueryImplementor;
|
||||||
|
import org.hibernate.type.descriptor.java.CoercionException;
|
||||||
|
import org.hibernate.type.descriptor.java.CoercionHelper;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for implicit widening coercions
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@DomainModel( annotatedClasses = CoercionTests.TheEntity.class )
|
||||||
|
@SessionFactory
|
||||||
|
public class CoercionTests {
|
||||||
|
final short shortValue = 1;
|
||||||
|
final byte byteValue = 1;
|
||||||
|
final int intValue = 1;
|
||||||
|
final long longValue = 1L;
|
||||||
|
final double doubleValue = 0.5;
|
||||||
|
final float floatValue = 0.5F;
|
||||||
|
|
||||||
|
final long largeLongValue = Integer.MAX_VALUE + 1L;
|
||||||
|
final float largeFloatValue = (float) Double.MAX_VALUE + 1.5F;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCoercibleDetection(SessionFactoryScope scope) {
|
||||||
|
final TypeConfiguration typeConfiguration = scope.getSessionFactory().getTypeConfiguration();
|
||||||
|
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
|
||||||
|
|
||||||
|
final JavaTypeDescriptor<Integer> integerType = jtdRegistry.resolveDescriptor( Integer.class );
|
||||||
|
final JavaTypeDescriptor<Long> longType = jtdRegistry.resolveDescriptor( Long.class );
|
||||||
|
final JavaTypeDescriptor<Double> doubleType = jtdRegistry.resolveDescriptor( Double.class );
|
||||||
|
final JavaTypeDescriptor<Float> floatType = jtdRegistry.resolveDescriptor( Float.class );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
checkIntegerConversions( integerType, session );
|
||||||
|
checkLongConversions( longType, session );
|
||||||
|
|
||||||
|
checkDoubleConversions( doubleType, session );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDoubleConversions(JavaTypeDescriptor<Double> doubleType, SessionImplementor session) {
|
||||||
|
assertThat( doubleType.coerce( (double) 1, session ), Matchers.is( 1.0 ) );
|
||||||
|
assertThat( doubleType.coerce( 1F, session ), Matchers.is( 1.0 ) );
|
||||||
|
assertThat( doubleType.coerce( doubleValue, session ), Matchers.is( doubleValue ) );
|
||||||
|
assertThat( doubleType.coerce( floatValue, session ), Matchers.is( doubleValue ) );
|
||||||
|
|
||||||
|
assertThat( doubleType.coerce( largeFloatValue, session ), Matchers.is( (double) largeFloatValue ) );
|
||||||
|
|
||||||
|
assertThat( doubleType.coerce( shortValue, session ), Matchers.is( 1.0 ) );
|
||||||
|
assertThat( doubleType.coerce( byteValue, session ), Matchers.is( 1.0 ) );
|
||||||
|
assertThat( doubleType.coerce( longValue, session ), Matchers.is( 1.0 ) );
|
||||||
|
|
||||||
|
assertThat( doubleType.coerce( BigInteger.ONE, session ), Matchers.is( 1.0 ) );
|
||||||
|
assertThat( doubleType.coerce( BigDecimal.ONE, session ), Matchers.is( 1.0 ) );
|
||||||
|
|
||||||
|
// negative checks
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIntegerConversions(JavaTypeDescriptor<Integer> integerType, SessionImplementor session) {
|
||||||
|
assertThat( integerType.coerce( intValue, session ), Matchers.is( intValue) );
|
||||||
|
|
||||||
|
assertThat( integerType.coerce( shortValue, session ), Matchers.is( intValue) );
|
||||||
|
assertThat( integerType.coerce( byteValue, session ), Matchers.is( intValue) );
|
||||||
|
|
||||||
|
assertThat( integerType.coerce( longValue, session ), Matchers.is( intValue) );
|
||||||
|
|
||||||
|
assertThat( integerType.coerce( (double) 1, session ), Matchers.is( intValue) );
|
||||||
|
assertThat( integerType.coerce( 1F, session ), Matchers.is( intValue) );
|
||||||
|
|
||||||
|
assertThat( integerType.coerce( BigInteger.ONE, session ), Matchers.is( intValue) );
|
||||||
|
assertThat( integerType.coerce( BigDecimal.ONE, session ), Matchers.is( intValue) );
|
||||||
|
|
||||||
|
// negative checks
|
||||||
|
checkDisallowedConversion( () -> integerType.coerce( largeLongValue, session ) );
|
||||||
|
checkDisallowedConversion( () -> integerType.coerce( largeFloatValue, session ) );
|
||||||
|
checkDisallowedConversion( () -> integerType.coerce( doubleValue, session ) );
|
||||||
|
checkDisallowedConversion( () -> integerType.coerce( floatValue, session ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkLongConversions(JavaTypeDescriptor<Long> longType, SessionImplementor session) {
|
||||||
|
assertThat( longType.coerce( longValue, session ), Matchers.is( longValue ) );
|
||||||
|
assertThat( longType.coerce( largeLongValue, session ), Matchers.is( largeLongValue ) );
|
||||||
|
|
||||||
|
assertThat( longType.coerce( intValue, session ), Matchers.is( longValue ) );
|
||||||
|
assertThat( longType.coerce( shortValue, session ), Matchers.is( longValue ) );
|
||||||
|
assertThat( longType.coerce( byteValue, session ), Matchers.is( longValue ) );
|
||||||
|
|
||||||
|
assertThat( longType.coerce( (double) 1, session ), Matchers.is( longValue ) );
|
||||||
|
assertThat( longType.coerce( 1F, session ), Matchers.is( longValue ) );
|
||||||
|
|
||||||
|
assertThat( longType.coerce( BigInteger.ONE, session ), Matchers.is( longValue ) );
|
||||||
|
assertThat( longType.coerce( BigDecimal.ONE, session ), Matchers.is( longValue ) );
|
||||||
|
|
||||||
|
// negative checks
|
||||||
|
checkDisallowedConversion( () -> longType.coerce( largeFloatValue, session ) );
|
||||||
|
checkDisallowedConversion( () -> longType.coerce( doubleValue, session ) );
|
||||||
|
checkDisallowedConversion( () -> longType.coerce( floatValue, session ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDisallowedConversion(CoercionHelper.Coercer callback) {
|
||||||
|
try {
|
||||||
|
callback.doCoercion();
|
||||||
|
fail( "Expecting coercion to fail" );
|
||||||
|
}
|
||||||
|
catch (CoercionException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoading(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byId( TheEntity.class ).load( 1L );
|
||||||
|
|
||||||
|
session.byId( TheEntity.class ).load( (byte) 1 );
|
||||||
|
session.byId( TheEntity.class ).load( (short) 1 );
|
||||||
|
session.byId( TheEntity.class ).load( 1 );
|
||||||
|
|
||||||
|
session.byId( TheEntity.class ).load( 1.0 );
|
||||||
|
session.byId( TheEntity.class ).load( 1.0F );
|
||||||
|
|
||||||
|
session.byId( TheEntity.class ).load( BigInteger.ONE );
|
||||||
|
session.byId( TheEntity.class ).load( BigDecimal.ONE );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byId( TheEntity.class ).getReference( 1L );
|
||||||
|
session.byId( TheEntity.class ).getReference( 1 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiIdLoading(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( 1L );
|
||||||
|
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( (byte) 1 );
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( (short) 1 );
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( 1 );
|
||||||
|
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( 1.0 );
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( 1.0F );
|
||||||
|
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( BigInteger.ONE );
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( BigDecimal.ONE );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( Arrays.asList( 1L ) );
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( Arrays.asList( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNaturalIdLoading(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( 1L );
|
||||||
|
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( (byte) 1 );
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( (short) 1 );
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( 1 );
|
||||||
|
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( 1.0 );
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( 1.0F );
|
||||||
|
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( BigInteger.ONE );
|
||||||
|
session.bySimpleNaturalId( TheEntity.class ).load( BigDecimal.ONE );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( Arrays.asList( 1L ) );
|
||||||
|
session.byMultipleIds( TheEntity.class ).multiLoad( Arrays.asList( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiNaturalIdLoading(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( 1L );
|
||||||
|
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( (byte) 1 );
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( (short) 1 );
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( 1 );
|
||||||
|
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( 1.0 );
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( 1.0F );
|
||||||
|
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( BigInteger.ONE );
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( BigDecimal.ONE );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( Arrays.asList( 1L ) );
|
||||||
|
session.byMultipleNaturalId( TheEntity.class ).enableOrderedReturn( false ).multiLoad( Arrays.asList( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryParameterIntegralWiden(SessionFactoryScope scope) {
|
||||||
|
final String qry = "select e from TheEntity e where e.longId = :id";
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
final QueryImplementor query = session.createQuery( qry );
|
||||||
|
|
||||||
|
query.setParameter( "id", 1L ).list();
|
||||||
|
|
||||||
|
query.setParameter( "id", 1 ).list();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryParameterIntegralNarrow(SessionFactoryScope scope) {
|
||||||
|
final String qry = "select e from TheEntity e where e.intValue = ?1";
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
final QueryImplementor query = session.createQuery( qry );
|
||||||
|
|
||||||
|
query.setParameter( 1, 1 ).list();
|
||||||
|
|
||||||
|
query.setParameter( 1, 1L ).list();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryParameterFloatingWiden(SessionFactoryScope scope) {
|
||||||
|
final String qry = "select e from TheEntity e where e.floatValue = :p";
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
final QueryImplementor query = session.createQuery( qry );
|
||||||
|
|
||||||
|
query.setParameter( "p", 0.5f ).list();
|
||||||
|
|
||||||
|
query.setParameter( "p", 0.5 ).list();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryParameterFloatingNarrow(SessionFactoryScope scope) {
|
||||||
|
final String qry = "select e from TheEntity e where e.doubleValue = :p";
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
(session) -> {
|
||||||
|
final QueryImplementor query = session.createQuery( qry );
|
||||||
|
|
||||||
|
query.setParameter( "p", 0.5 ).list();
|
||||||
|
|
||||||
|
query.setParameter( "p", 0.5f ).list();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "TheEntity" )
|
||||||
|
@Table( name = "the_entity" )
|
||||||
|
public static class TheEntity {
|
||||||
|
@Id
|
||||||
|
private Long longId;
|
||||||
|
@NaturalId
|
||||||
|
private Long longNaturalId;
|
||||||
|
private Integer intValue;
|
||||||
|
private Float floatValue;
|
||||||
|
private Double doubleValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue