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
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ private Component getOrCreateCompositeId(RootClass rootClass) {
buildingContext
);
rootClass.setIdentifier( identifier );
identifier.setNullValue( "undefined" );
identifier.setNullValueUndefined();
rootClass.setEmbeddedIdentifier( true );
rootClass.setIdentifierMapper( identifier );
return identifier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ private void bindEntityVersion(
versionValue.setNullValue( versionAttributeSource.getUnsavedValue() );
}
else {
versionValue.setNullValue( "undefined" );
versionValue.setNullValueUndefined();
}
if ( versionAttributeSource.getSource().equals("db") ) {
property.setValueGeneratorCreator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,17 @@ public interface ClassLoaderService extends ResourceLocator, ResourceStreamLocat

@SuppressWarnings("unchecked")
default <T> Class<T> classForTypeName(String className) {
switch ( className ) {
case "boolean":
return (Class<T>) boolean.class;
case "byte":
return (Class<T>) byte.class;
case "char":
return (Class<T>) char.class;
case "short":
return (Class<T>) short.class;
case "int":
return (Class<T>) int.class;
case "float":
return (Class<T>) float.class;
case "long":
return (Class<T>) long.class;
case "double":
return (Class<T>) double.class;
default:
return classForName( className );
}
return (Class<T>) switch ( className ) {
case "boolean" -> boolean.class;
case "byte" -> byte.class;
case "char" -> char.class;
case "short" -> short.class;
case "int" -> int.class;
case "float" -> float.class;
case "long" -> long.class;
case "double" -> double.class;
default -> classForName( className );
};
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@

import java.util.function.Supplier;

import org.hibernate.MappingException;
import org.hibernate.SharedSessionContract;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.IdentifierValue;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionDelegatorBaseImpl;
import org.hibernate.engine.spi.VersionValue;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.KeyValue.NullValueSemantic;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.VersionJavaType;
Expand All @@ -36,38 +32,34 @@ public class UnsavedValueFactory {
*/
public static IdentifierValue getUnsavedIdentifierValue(
KeyValue bootIdMapping,
JavaType<?> idJtd,
JavaType<?> idJavaType,
Getter getter,
Supplier<?> templateInstanceAccess) {
final String unsavedValue = bootIdMapping.getNullValue();
final NullValueSemantic nullValueSemantic = bootIdMapping.getNullValueSemantic();
return nullValueSemantic == null
? inferUnsavedIdentifierValue( idJavaType, getter, templateInstanceAccess )
: switch ( nullValueSemantic ) {
case UNDEFINED -> IdentifierValue.UNDEFINED;
case NULL -> IdentifierValue.NULL;
case ANY -> IdentifierValue.ANY;
case NONE -> IdentifierValue.NONE;
case VALUE -> new IdentifierValue( idJavaType.fromString( bootIdMapping.getNullValue() ) );
default -> throw new IllegalArgumentException( "Illegal null-value semantic: " + nullValueSemantic );
};
}

if ( unsavedValue == null ) {
if ( getter != null && templateInstanceAccess != null ) {
// use the id value of a newly instantiated instance as the unsaved-value
final Object templateInstance = templateInstanceAccess.get();
final Object defaultValue = getter.get( templateInstance );
return new IdentifierValue( defaultValue );
}
else if ( idJtd instanceof PrimitiveJavaType ) {
return new IdentifierValue( ( (PrimitiveJavaType<?>) idJtd ).getDefaultValue() );
}
else {
return IdentifierValue.NULL;
}
private static IdentifierValue inferUnsavedIdentifierValue(
JavaType<?> idJavaType, Getter getter, Supplier<?> templateInstanceAccess) {
if ( getter != null && templateInstanceAccess != null ) {
// use the id value of a newly instantiated instance as the unsaved-value
final Object defaultValue = getter.get( templateInstanceAccess.get() );
return new IdentifierValue( defaultValue );
}
else if ( idJavaType instanceof PrimitiveJavaType<?> primitiveJavaType ) {
return new IdentifierValue( primitiveJavaType.getDefaultValue() );
}
else {
switch (unsavedValue) {
case "null":
return IdentifierValue.NULL;
case "undefined":
return IdentifierValue.UNDEFINED;
case "none":
return IdentifierValue.NONE;
case "any":
return IdentifierValue.ANY;
default:
return new IdentifierValue( idJtd.fromString( unsavedValue ) );
}
return IdentifierValue.NULL;
}
}

Expand All @@ -80,65 +72,36 @@ else if ( idJtd instanceof PrimitiveJavaType ) {
*/
public static <T> VersionValue getUnsavedVersionValue(
KeyValue bootVersionMapping,
VersionJavaType<T> jtd,
VersionJavaType<T> versionJavaType,
Getter getter,
Supplier<?> templateInstanceAccess) {
final String unsavedValue = bootVersionMapping.getNullValue();
if ( unsavedValue == null ) {
if ( getter != null && templateInstanceAccess != null ) {
final Object templateInstance = templateInstanceAccess.get();
@SuppressWarnings("unchecked")
final T defaultValue = (T) getter.get( templateInstance );
// if the version of a newly instantiated object is null
// or a negative number, use that value as the unsaved-value,
// otherwise assume it's the initial version set by program
return isNullInitialVersion( defaultValue )
? new VersionValue( defaultValue )
: VersionValue.UNDEFINED;
}
else {
return VersionValue.UNDEFINED;
}
}
else {
switch (unsavedValue) {
case "undefined":
return VersionValue.UNDEFINED;
case "null":
return VersionValue.NULL;
case "negative":
return VersionValue.NEGATIVE;
default:
final NullValueSemantic nullValueSemantic = bootVersionMapping.getNullValueSemantic();
return nullValueSemantic == null
? inferUnsavedVersionValue( versionJavaType, getter, templateInstanceAccess )
: switch ( nullValueSemantic ) {
case UNDEFINED -> VersionValue.UNDEFINED;
case NULL -> VersionValue.NULL;
case NEGATIVE -> VersionValue.NEGATIVE;
// this should not happen since the DTD prevents it
throw new MappingException("Could not parse version unsaved-value: " + unsavedValue);
}
}

case VALUE -> new VersionValue( versionJavaType.fromString( bootVersionMapping.getNullValue() ) );
default -> throw new IllegalArgumentException( "Illegal null-value semantic: " + nullValueSemantic );
};
}

private static SharedSessionDelegatorBaseImpl mockSession(SessionFactoryImplementor sessionFactory) {
return new SharedSessionDelegatorBaseImpl(null) {

@Override
protected SharedSessionContract delegate() {
throw new UnsupportedOperationException( "Operation not supported" );
}

@Override
public SessionFactoryImplementor getFactory() {
return sessionFactory;
}

@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}

@Override
public JdbcServices getJdbcServices() {
return sessionFactory.getJdbcServices();
}
};
private static VersionValue inferUnsavedVersionValue(
VersionJavaType<?> versionJavaType, Getter getter, Supplier<?> templateInstanceAccess) {
if ( getter != null && templateInstanceAccess != null ) {
final Object defaultValue = getter.get( templateInstanceAccess.get() );
// if the version of a newly instantiated object is null
// or a negative number, use that value as the unsaved-value,
// otherwise assume it's the initial version set by program
return isNullInitialVersion( defaultValue )
? new VersionValue( defaultValue )
: VersionValue.UNDEFINED;
}
else {
return VersionValue.UNDEFINED;
}
}

private UnsavedValueFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,10 +720,6 @@ void cannotResolveNonNullableTransientDependencies(
@Message(value = "Creating pooled optimizer (lo) with [incrementSize=%s; returnClass=%s]", id = 467)
void creatingPooledLoOptimizer(int incrementSize, String name);

@LogMessage(level = WARN)
@Message(value = "Unable to interpret type [%s] as an AttributeConverter due to an exception: %s", id = 468)
void logBadHbmAttributeConverterType(String type, String exceptionMessage);

@LogMessage(level = WARN)
@Message(value = "An unexpected session is defined for a collection, but the collection is not connected to that session. A persistent collection may only be associated with one session at a time. Overwriting session. %s", id = 470)
void logUnexpectedSessionInCollectionNotConnected(String msg);
Expand Down
76 changes: 27 additions & 49 deletions hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hibernate.boot.internal.ClassmateContext;
import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.convert.internal.AutoApplicableConverterDescriptorBypassedImpl;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
import org.hibernate.boot.model.convert.internal.InstanceBasedConverterDescriptor;
import org.hibernate.boot.model.convert.spi.AutoApplicableConverterDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
Expand All @@ -39,8 +38,6 @@
import org.hibernate.engine.jdbc.Size;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectablePath;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
Expand Down Expand Up @@ -80,7 +77,10 @@
import jakarta.persistence.TemporalType;

import static java.lang.Boolean.parseBoolean;
import static org.hibernate.boot.model.convert.spi.ConverterDescriptor.TYPE_NAME_PREFIX;
import static org.hibernate.internal.util.ReflectHelper.reflectedPropertyType;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
import static org.hibernate.mapping.MappingHelper.injectParameters;

Expand Down Expand Up @@ -217,10 +217,7 @@ public void setImplicitJavaTypeAccess(Function<TypeConfiguration, java.lang.refl
}

public Selectable getColumn() {
if ( getColumnSpan() == 0 ) {
return null;
}
return getColumn( 0 );
return getColumnSpan() == 0 ? null : getColumn( 0 );
}

public java.lang.reflect.Type getResolvedJavaType() {
Expand Down Expand Up @@ -748,8 +745,7 @@ else if ( implicitJavaTypeAccess != null ) {
return implicitJavaTypeAccess.apply(typeConfiguration);
}
else if ( ownerName != null && propertyName != null ) {
return reflectedPropertyType( ownerName, propertyName,
getServiceRegistry().requireService( ClassLoaderService.class ) );
return reflectedPropertyType( ownerName, propertyName, classLoaderService() );
}
else {
return null;
Expand Down Expand Up @@ -835,7 +831,7 @@ public TypeConfiguration getTypeConfiguration() {
// 3) basic type "resolution key"
// 4) UserType or BasicType class name - directly, or through a TypeDefinition

if ( name.startsWith( ConverterDescriptor.TYPE_NAME_PREFIX ) ) {
if ( name.startsWith( TYPE_NAME_PREFIX ) ) {
return NamedConverterResolution.from(
name,
explicitJtdAccess,
Expand Down Expand Up @@ -902,13 +898,12 @@ public TypeConfiguration getTypeConfiguration() {


// see if the name is a UserType or BasicType implementor class name
final ClassLoaderService cls = serviceRegistry.requireService( ClassLoaderService.class );
final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class );
try {
final Class<?> typeNamedClass = cls.classForName( name );

final Class<?> typeNamedClass = classLoaderService.classForName( name );
// if there are no local config params, register an implicit TypeDefinition for this custom type .
// later uses may find it and re-use its cacheable reference...
if ( CollectionHelper.isEmpty( localTypeParams ) ) {
if ( isEmpty( localTypeParams ) ) {
final TypeDefinition implicitDefinition = new TypeDefinition(
name,
typeNamedClass,
Expand Down Expand Up @@ -988,19 +983,15 @@ public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
public static TimeZoneStorageStrategy timeZoneStorageStrategy(
TimeZoneStorageType timeZoneStorageType,
MetadataBuildingContext buildingContext) {
if ( timeZoneStorageType != null ) {
switch ( timeZoneStorageType ) {
case COLUMN:
return TimeZoneStorageStrategy.COLUMN;
case NATIVE:
return TimeZoneStorageStrategy.NATIVE;
case NORMALIZE:
return TimeZoneStorageStrategy.NORMALIZE;
case NORMALIZE_UTC:
return TimeZoneStorageStrategy.NORMALIZE_UTC;
}
}
return buildingContext.getBuildingOptions().getDefaultTimeZoneStorage();
return timeZoneStorageType == null
? buildingContext.getBuildingOptions().getDefaultTimeZoneStorage()
: switch ( timeZoneStorageType ) {
case COLUMN -> TimeZoneStorageStrategy.COLUMN;
case NATIVE -> TimeZoneStorageStrategy.NATIVE;
case NORMALIZE -> TimeZoneStorageStrategy.NORMALIZE;
case NORMALIZE_UTC -> TimeZoneStorageStrategy.NORMALIZE_UTC;
case AUTO, DEFAULT -> buildingContext.getBuildingOptions().getDefaultTimeZoneStorage();
};
}

public void setExplicitTypeParams(Map<String,String> explicitLocalTypeParams) {
Expand All @@ -1012,29 +1003,16 @@ public void setExplicitTypeName(String typeName) {
}

public void setTypeName(String typeName) {
if ( StringHelper.isNotEmpty( typeName ) ) {
if ( typeName.startsWith( ConverterDescriptor.TYPE_NAME_PREFIX ) ) {
final String converterClassName = typeName.substring( ConverterDescriptor.TYPE_NAME_PREFIX.length() );
final ClassLoaderService cls = getServiceRegistry().requireService( ClassLoaderService.class );
try {
final Class<AttributeConverter<?,?>> converterClass = cls.classForName( converterClassName );
setAttributeConverterDescriptor( new ClassBasedConverterDescriptor(
converterClass,
false,
getBuildingContext().getBootstrapContext().getClassmateContext()
) );
return;
}
catch (Exception e) {
log.logBadHbmAttributeConverterType( typeName, e.getMessage() );
}
}
else {
setExplicitTypeName( typeName );
}
if ( isEmpty( typeName ) ) {
super.setTypeName( typeName );
}
else if ( typeName.startsWith( TYPE_NAME_PREFIX ) ) {
setAttributeConverterDescriptor( typeName );
}
else {
setExplicitTypeName( typeName );
super.setTypeName( typeName );
}

super.setTypeName( typeName );
}

private static int COUNTER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,18 @@ public interface KeyValue extends Value {

boolean isCascadeDeleteEnabled();

enum NullValueSemantic { VALUE, NULL, NEGATIVE, UNDEFINED, NONE, ANY }

NullValueSemantic getNullValueSemantic();

String getNullValue();

boolean isUpdateable();

/**
* @deprecated No longer called, except from tests.
* Use {@link #createGenerator(Dialect, RootClass, Property, GeneratorSettings)}
*/
@Deprecated(since = "7.0", forRemoval = true)
Generator createGenerator(Dialect dialect, RootClass rootClass);

Expand Down
Loading
Loading