Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 124 additions & 98 deletions hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.hibernate.engine.jdbc.Size;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.JdbcMapping;
Expand Down Expand Up @@ -82,6 +81,7 @@
import jakarta.persistence.TemporalType;

import static java.lang.Boolean.parseBoolean;
import static org.hibernate.internal.util.ReflectHelper.reflectedPropertyType;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
import static org.hibernate.mapping.MappingHelper.injectParameters;

Expand All @@ -103,6 +103,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
private Function<TypeConfiguration, java.lang.reflect.Type> implicitJavaTypeAccess;

private EnumType enumerationStyle;
@SuppressWarnings("deprecation")
private TemporalType temporalPrecision;
private TimeZoneStorageType timeZoneStorageType;
private boolean isSoftDelete;
Expand Down Expand Up @@ -234,8 +235,7 @@ public java.lang.reflect.Type getResolvedJavaType() {
public long getColumnLength() {
final Selectable selectable = getColumn();
if ( selectable instanceof Column ) {
final Column column = (Column) selectable;
final Long length = column.getLength();
final Long length = ( (Column) selectable ).getLength();
return length == null ? NO_COLUMN_LENGTH : length;
}
else {
Expand All @@ -248,8 +248,9 @@ public int getColumnPrecision() {
final Selectable selectable = getColumn();
if ( selectable instanceof Column ) {
final Column column = (Column) selectable;
if ( column.getTemporalPrecision() != null ) {
return column.getTemporalPrecision();
final Integer temporalPrecision = column.getTemporalPrecision();
if ( temporalPrecision != null ) {
return temporalPrecision;
}
final Integer precision = column.getPrecision();
return precision == null ? NO_COLUMN_PRECISION : precision;
Expand All @@ -263,8 +264,7 @@ public int getColumnPrecision() {
public int getColumnScale() {
final Selectable selectable = getColumn();
if ( selectable instanceof Column ) {
final Column column = (Column) selectable;
final Integer scale = column.getScale();
final Integer scale = ( (Column) selectable ).getScale();
return scale == null ? NO_COLUMN_SCALE : scale;
}
else {
Expand All @@ -284,8 +284,9 @@ public void copyTypeFrom(SimpleValue sourceValue) {
super.copyTypeFrom( sourceValue );
if ( sourceValue instanceof BasicValue ) {
final BasicValue basicValue = (BasicValue) sourceValue;
this.resolution = basicValue.resolution;
this.implicitJavaTypeAccess = (typeConfiguration) -> basicValue.implicitJavaTypeAccess.apply( typeConfiguration );
resolution = basicValue.resolution;
implicitJavaTypeAccess =
typeConfiguration -> basicValue.implicitJavaTypeAccess.apply( typeConfiguration );
}
}

Expand Down Expand Up @@ -447,55 +448,71 @@ && parseBoolean( typeParameters.getProperty(DynamicParameterizedType.IS_DYNAMIC)
getBuildingContext()
);
}

if ( isVersion() ) {
else if ( isVersion() ) {
return VersionResolution.from( implicitJavaTypeAccess, timeZoneStorageType, getBuildingContext() );
}
else {
// determine JavaType if we can
final BasicJavaType<?> explicitJavaType = getExplicitJavaType();
final JavaType<?> javaType = determineJavaType( explicitJavaType );
final ConverterDescriptor converterDescriptor = getConverterDescriptor( javaType );
return converterDescriptor != null
? converterResolution( javaType, converterDescriptor )
: resolution( explicitJavaType, javaType );
}
}

// determine JavaType if we can
final BasicJavaType<?> explicitJavaType = explicitJavaTypeAccess == null
? null
private BasicJavaType<?> getExplicitJavaType() {
return explicitJavaTypeAccess == null ? null
: explicitJavaTypeAccess.apply( getTypeConfiguration() );
}

JavaType<?> javaType = determineJavaType( explicitJavaType );
ConverterDescriptor attributeConverterDescriptor = getAttributeConverterDescriptor();

private ConverterDescriptor getConverterDescriptor(JavaType<?> javaType) {
final ConverterDescriptor converterDescriptor = getAttributeConverterDescriptor();
if ( isSoftDelete() ) {
assert attributeConverterDescriptor != null;
final boolean conversionWasUnspecified = SoftDelete.UnspecifiedConversion.class.equals( attributeConverterDescriptor.getAttributeConverterClass() );
if ( conversionWasUnspecified ) {
final JdbcType jdbcType = BooleanJdbcType.INSTANCE.resolveIndicatedType( this, javaType );
if ( jdbcType.isNumber() ) {
attributeConverterDescriptor = new InstanceBasedConverterDescriptor(
NumericBooleanConverter.INSTANCE,
getBuildingContext().getBootstrapContext().getClassmateContext()
);
}
else if ( jdbcType.isString() ) {
// here we pick 'T' / 'F' storage, though 'Y' / 'N' is equally valid - its 50/50
attributeConverterDescriptor = new InstanceBasedConverterDescriptor(
TrueFalseConverter.INSTANCE,
getBuildingContext().getBootstrapContext().getClassmateContext()
);
}
else {
// should indicate BIT or BOOLEAN == no conversion needed
// - we still create the converter to properly set up JDBC type, etc
attributeConverterDescriptor = new InstanceBasedConverterDescriptor(
PassThruSoftDeleteConverter.INSTANCE,
getBuildingContext().getBootstrapContext().getClassmateContext()
);
}
}
assert converterDescriptor != null;
final ConverterDescriptor softDeleteConverterDescriptor =
getSoftDeleteConverterDescriptor( converterDescriptor, javaType);
return getSoftDeleteStrategy() == SoftDeleteType.ACTIVE
? new ReversedConverterDescriptor<>( softDeleteConverterDescriptor )
: softDeleteConverterDescriptor;
}
else {
return converterDescriptor;
}
}

if ( getSoftDeleteStrategy() == SoftDeleteType.ACTIVE ) {
attributeConverterDescriptor = new ReversedConverterDescriptor<>( attributeConverterDescriptor );
private ConverterDescriptor getSoftDeleteConverterDescriptor(
ConverterDescriptor attributeConverterDescriptor, JavaType<?> javaType) {
final boolean conversionWasUnspecified =
SoftDelete.UnspecifiedConversion.class.equals( attributeConverterDescriptor.getAttributeConverterClass() );
if ( conversionWasUnspecified ) {
final JdbcType jdbcType = BooleanJdbcType.INSTANCE.resolveIndicatedType( this, javaType);
if ( jdbcType.isNumber() ) {
return new InstanceBasedConverterDescriptor(
NumericBooleanConverter.INSTANCE,
getBuildingContext().getBootstrapContext().getClassmateContext()
);
}
else if ( jdbcType.isString() ) {
// here we pick 'T' / 'F' storage, though 'Y' / 'N' is equally valid - its 50/50
return new InstanceBasedConverterDescriptor(
TrueFalseConverter.INSTANCE,
getBuildingContext().getBootstrapContext().getClassmateContext()
);
}
else {
// should indicate BIT or BOOLEAN == no conversion needed
// - we still create the converter to properly set up JDBC type, etc
return new InstanceBasedConverterDescriptor(
PassThruSoftDeleteConverter.INSTANCE,
getBuildingContext().getBootstrapContext().getClassmateContext()
);
}
}

return attributeConverterDescriptor != null
? converterResolution( javaType, attributeConverterDescriptor )
: resolution( explicitJavaType, javaType );
else {
return attributeConverterDescriptor;
}
}

private static class ReversedConverterDescriptor<R> implements ConverterDescriptor {
Expand Down Expand Up @@ -680,11 +697,10 @@ private Resolution<?> converterResolution(JavaType<?> javaType, ConverterDescrip
&& !attributeConverterDescriptor.getDomainValueResolvedType().getErasedType()
.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
// In this case, the converter applies to the element of a BasicPluralJavaType
final BasicPluralJavaType<?> containerJtd = (BasicPluralJavaType<?>) javaType;
final BasicType registeredElementType = converterResolution.getLegacyResolvedBasicType();
final Selectable column = getColumn();
final BasicType<?> registeredType = registeredElementType == null ? null
: containerJtd.resolveType(
: ( (BasicPluralJavaType<?>) javaType ).resolveType(
getTypeConfiguration(),
getDialect(),
registeredElementType,
Expand Down Expand Up @@ -730,66 +746,76 @@ private JavaType<?> determineJavaType(JavaType<?> explicitJavaType) {
}

private JavaType<?> determineReflectedJavaType() {
final java.lang.reflect.Type impliedJavaType;

final TypeConfiguration typeConfiguration = getTypeConfiguration();
final java.lang.reflect.Type impliedJavaType = impliedJavaType( typeConfiguration );
if ( impliedJavaType == null ) {
return null;
}
else {
resolvedJavaType = impliedJavaType;
return javaType( typeConfiguration, impliedJavaType );
}
}

private java.lang.reflect.Type impliedJavaType(TypeConfiguration typeConfiguration) {
if ( resolvedJavaType != null ) {
impliedJavaType = resolvedJavaType;
return resolvedJavaType;
}
else if ( implicitJavaTypeAccess != null ) {
impliedJavaType = implicitJavaTypeAccess.apply( typeConfiguration );
return implicitJavaTypeAccess.apply(typeConfiguration);
}
else if ( ownerName != null && propertyName != null ) {
impliedJavaType = ReflectHelper.reflectedPropertyType(
ownerName,
propertyName,
getServiceRegistry().requireService( ClassLoaderService.class )
);
return reflectedPropertyType( ownerName, propertyName,
getServiceRegistry().requireService( ClassLoaderService.class ) );
}
else {
return null;
}
}

resolvedJavaType = impliedJavaType;
private JavaType<Object> javaType(TypeConfiguration typeConfiguration, java.lang.reflect.Type impliedJavaType) {
final JavaType<Object> javaType = typeConfiguration.getJavaTypeRegistry().findDescriptor( impliedJavaType );
return javaType == null ? specialJavaType( typeConfiguration, impliedJavaType ) : javaType;
}

if ( impliedJavaType == null ) {
return null;
private JavaType<Object> specialJavaType(
TypeConfiguration typeConfiguration,
java.lang.reflect.Type impliedJavaType) {
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
if ( jdbcTypeCode != null ) {
// Construct special JavaType instances for JSON/XML types which can report recommended JDBC types
// and implement toString/fromString as well as copying based on FormatMapper operations
switch ( jdbcTypeCode ) {
case SqlTypes.JSON:
final JavaType<Object> jsonJavaType =
new JsonJavaType<>( impliedJavaType,
mutabilityPlan( typeConfiguration, impliedJavaType ),
typeConfiguration );
javaTypeRegistry.addDescriptor( jsonJavaType );
return jsonJavaType;
case SqlTypes.SQLXML:
final JavaType<Object> xmlJavaType =
new XmlJavaType<>( impliedJavaType,
mutabilityPlan( typeConfiguration, impliedJavaType ),
typeConfiguration );
javaTypeRegistry.addDescriptor( xmlJavaType );
return xmlJavaType;
}
}
return javaTypeRegistry.resolveDescriptor( impliedJavaType );
}

final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
final JavaType<Object> javaType = javaTypeRegistry.findDescriptor( impliedJavaType );
final MutabilityPlan<Object> explicitMutabilityPlan = explicitMutabilityPlanAccess != null
? explicitMutabilityPlanAccess.apply( typeConfiguration )
: null;
final MutabilityPlan<Object> determinedMutabilityPlan = explicitMutabilityPlan != null
private MutabilityPlan<Object> mutabilityPlan(
TypeConfiguration typeConfiguration, java.lang.reflect.Type impliedJavaType) {
final MutabilityPlan<Object> explicitMutabilityPlan = getExplicitMutabilityPlan();
return explicitMutabilityPlan != null
? explicitMutabilityPlan
: RegistryHelper.INSTANCE.determineMutabilityPlan( impliedJavaType, typeConfiguration );
if ( javaType == null ) {
if ( jdbcTypeCode != null ) {
// Construct special JavaType instances for JSON/XML types which can report recommended JDBC types
// and implement toString/fromString as well as copying based on FormatMapper operations
switch ( jdbcTypeCode ) {
case SqlTypes.JSON:
final JavaType<Object> jsonJavaType = new JsonJavaType<>(
impliedJavaType,
determinedMutabilityPlan,
typeConfiguration
);
javaTypeRegistry.addDescriptor( jsonJavaType );
return jsonJavaType;
case SqlTypes.SQLXML:
final JavaType<Object> xmlJavaType = new XmlJavaType<>(
impliedJavaType,
determinedMutabilityPlan,
typeConfiguration
);
javaTypeRegistry.addDescriptor( xmlJavaType );
return xmlJavaType;
}
}
return javaTypeRegistry.resolveDescriptor( impliedJavaType );
}
return javaType;
}

private MutabilityPlan<Object> getExplicitMutabilityPlan() {
return explicitMutabilityPlanAccess == null ? null
: explicitMutabilityPlanAccess.apply( getTypeConfiguration() );
}

private static Resolution<?> interpretExplicitlyNamedType(
Expand Down Expand Up @@ -1066,8 +1092,7 @@ private UserType<?> getConfiguredUserTypeBean(Class<? extends UserType<?>> expli
: getUserTypeBean( explicitCustomType, properties ).getBeanInstance();

if ( typeInstance instanceof TypeConfigurationAware ) {
final TypeConfigurationAware configurationAware = (TypeConfigurationAware) typeInstance;
configurationAware.setTypeConfiguration( getTypeConfiguration() );
( (TypeConfigurationAware) typeInstance ).setTypeConfiguration( getTypeConfiguration() );
}

if ( typeInstance instanceof DynamicParameterizedType ) {
Expand Down Expand Up @@ -1097,11 +1122,12 @@ private <T> ManagedBean<T> getUserTypeBean(Class<T> explicitCustomType, Properti
}
}

@SuppressWarnings("deprecation")
public void setTemporalPrecision(TemporalType temporalPrecision) {
this.temporalPrecision = temporalPrecision;
}

@Override
@Override @SuppressWarnings("deprecation")
public TemporalType getTemporalPrecision() {
return temporalPrecision;
}
Expand Down
Loading