move away from magical unsaved-value strings
introduce NullValueSemantic Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
529cb279d0
commit
cb38afc773
|
@ -385,7 +385,7 @@ public class PropertyBinder {
|
|||
buildingContext
|
||||
);
|
||||
rootClass.setIdentifier( identifier );
|
||||
identifier.setNullValue( "undefined" );
|
||||
identifier.setNullValueUndefined();
|
||||
rootClass.setEmbeddedIdentifier( true );
|
||||
rootClass.setIdentifierMapper( identifier );
|
||||
return identifier;
|
||||
|
|
|
@ -923,7 +923,7 @@ public class ModelBinder {
|
|||
versionValue.setNullValue( versionAttributeSource.getUnsavedValue() );
|
||||
}
|
||||
else {
|
||||
versionValue.setNullValue( "undefined" );
|
||||
versionValue.setNullValueUndefined();
|
||||
}
|
||||
if ( versionAttributeSource.getSource().equals("db") ) {
|
||||
property.setValueGeneratorCreator(
|
||||
|
|
|
@ -6,10 +6,10 @@ package org.hibernate.engine.internal;
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.spi.IdentifierValue;
|
||||
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;
|
||||
|
@ -35,28 +35,31 @@ public class UnsavedValueFactory {
|
|||
JavaType<?> idJavaType,
|
||||
Getter getter,
|
||||
Supplier<?> templateInstanceAccess) {
|
||||
final String unsavedValue = bootIdMapping.getNullValue();
|
||||
if ( unsavedValue == null ) {
|
||||
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 {
|
||||
return IdentifierValue.NULL;
|
||||
}
|
||||
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 );
|
||||
};
|
||||
}
|
||||
|
||||
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 {
|
||||
return switch ( unsavedValue ) {
|
||||
case "null" -> IdentifierValue.NULL;
|
||||
case "undefined" -> IdentifierValue.UNDEFINED;
|
||||
case "none" -> IdentifierValue.NONE;
|
||||
case "any" -> IdentifierValue.ANY;
|
||||
default -> new IdentifierValue( idJavaType.fromString( unsavedValue ) );
|
||||
};
|
||||
return IdentifierValue.NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,31 +75,33 @@ public class UnsavedValueFactory {
|
|||
VersionJavaType<T> versionJavaType,
|
||||
Getter getter,
|
||||
Supplier<?> templateInstanceAccess) {
|
||||
final String unsavedValue = bootVersionMapping.getNullValue();
|
||||
if ( unsavedValue == null ) {
|
||||
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;
|
||||
}
|
||||
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
|
||||
case VALUE -> new VersionValue( versionJavaType.fromString( bootVersionMapping.getNullValue() ) );
|
||||
default -> throw new IllegalArgumentException( "Illegal null-value semantic: " + nullValueSemantic );
|
||||
};
|
||||
}
|
||||
|
||||
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 {
|
||||
// this should not happen since the DTD prevents it
|
||||
return switch ( unsavedValue ) {
|
||||
case "undefined" -> VersionValue.UNDEFINED;
|
||||
case "null" -> VersionValue.NULL;
|
||||
case "negative" -> VersionValue.NEGATIVE;
|
||||
default -> throw new MappingException( "Could not parse version unsaved-value: " + unsavedValue );
|
||||
};
|
||||
return VersionValue.UNDEFINED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private UnsavedValueFactory() {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ public abstract class SimpleValue implements KeyValue {
|
|||
private boolean isNationalized;
|
||||
private boolean isLob;
|
||||
|
||||
private NullValueSemantic nullValueSemantic;
|
||||
private String nullValue;
|
||||
|
||||
private Table table;
|
||||
|
@ -410,8 +411,8 @@ public abstract class SimpleValue implements KeyValue {
|
|||
final IdGeneratorCreationContext context =
|
||||
new IdGeneratorCreationContext( rootClass, property, defaults );
|
||||
final Generator generator = customIdGeneratorCreator.createGenerator( context );
|
||||
if ( generator.allowAssignedIdentifiers() && getNullValue() == null ) {
|
||||
setNullValue( "undefined" );
|
||||
if ( generator.allowAssignedIdentifiers() && nullValue == null ) {
|
||||
setNullValueUndefined();
|
||||
}
|
||||
return generator;
|
||||
}
|
||||
|
@ -449,17 +450,73 @@ public abstract class SimpleValue implements KeyValue {
|
|||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* The property or field value which indicates that field
|
||||
* or property has never been set.
|
||||
*
|
||||
* @see org.hibernate.engine.internal.UnsavedValueFactory
|
||||
* @see org.hibernate.engine.spi.IdentifierValue
|
||||
* @see org.hibernate.engine.spi.VersionValue
|
||||
*/
|
||||
@Override
|
||||
public String getNullValue() {
|
||||
return nullValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the nullValue.
|
||||
* @param nullValue The nullValue to set
|
||||
* Set the property or field value indicating that field
|
||||
* or property has never been set.
|
||||
*
|
||||
* @see org.hibernate.engine.internal.UnsavedValueFactory
|
||||
* @see org.hibernate.engine.spi.IdentifierValue
|
||||
* @see org.hibernate.engine.spi.VersionValue
|
||||
*/
|
||||
public void setNullValue(String nullValue) {
|
||||
this.nullValue = nullValue;
|
||||
nullValueSemantic = switch (nullValue) {
|
||||
// magical values (legacy of hbm.xml)
|
||||
case "null" -> NullValueSemantic.NULL;
|
||||
case "none" -> NullValueSemantic.NONE;
|
||||
case "any" -> NullValueSemantic.ANY;
|
||||
case "undefined" -> NullValueSemantic.UNDEFINED;
|
||||
default -> NullValueSemantic.VALUE;
|
||||
};
|
||||
if ( nullValueSemantic == NullValueSemantic.VALUE ) {
|
||||
this.nullValue = nullValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The rule for determining if the field or
|
||||
* property has been set.
|
||||
*
|
||||
* @see org.hibernate.engine.internal.UnsavedValueFactory
|
||||
*/
|
||||
@Override
|
||||
public NullValueSemantic getNullValueSemantic() {
|
||||
return nullValueSemantic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the rule for determining if the field or
|
||||
* property has been set.
|
||||
*
|
||||
* @see org.hibernate.engine.internal.UnsavedValueFactory
|
||||
*/
|
||||
public void setNullValueSemantic(NullValueSemantic nullValueSemantic) {
|
||||
this.nullValueSemantic = nullValueSemantic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that there is no well-defined property or
|
||||
* field value indicating that field or property has never
|
||||
* been set.
|
||||
*
|
||||
* @see org.hibernate.engine.internal.UnsavedValueFactory
|
||||
* @see org.hibernate.engine.spi.IdentifierValue#UNDEFINED
|
||||
* @see org.hibernate.engine.spi.VersionValue#UNDEFINED
|
||||
*/
|
||||
public void setNullValueUndefined() {
|
||||
nullValueSemantic = NullValueSemantic.UNDEFINED;
|
||||
}
|
||||
|
||||
public String getForeignKeyName() {
|
||||
|
|
Loading…
Reference in New Issue