Skip to content

Commit 58dc00c

Browse files
committed
move away from magical unsaved-value strings
introduce NullValueSemantic Signed-off-by: Gavin King <[email protected]>
1 parent 357b275 commit 58dc00c

File tree

5 files changed

+116
-50
lines changed

5 files changed

+116
-50
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ private Component getOrCreateCompositeId(RootClass rootClass) {
385385
buildingContext
386386
);
387387
rootClass.setIdentifier( identifier );
388-
identifier.setNullValue( "undefined" );
388+
identifier.setNullValueUndefined();
389389
rootClass.setEmbeddedIdentifier( true );
390390
rootClass.setIdentifierMapper( identifier );
391391
return identifier;

hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ private void bindEntityVersion(
923923
versionValue.setNullValue( versionAttributeSource.getUnsavedValue() );
924924
}
925925
else {
926-
versionValue.setNullValue( "undefined" );
926+
versionValue.setNullValueUndefined();
927927
}
928928
if ( versionAttributeSource.getSource().equals("db") ) {
929929
property.setValueGeneratorCreator(

hibernate-core/src/main/java/org/hibernate/engine/internal/UnsavedValueFactory.java

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import java.util.function.Supplier;
88

9-
import org.hibernate.MappingException;
109
import org.hibernate.engine.spi.IdentifierValue;
1110
import org.hibernate.engine.spi.VersionValue;
1211
import org.hibernate.mapping.KeyValue;
@@ -35,28 +34,30 @@ public static IdentifierValue getUnsavedIdentifierValue(
3534
JavaType<?> idJavaType,
3635
Getter getter,
3736
Supplier<?> templateInstanceAccess) {
38-
final String unsavedValue = bootIdMapping.getNullValue();
39-
if ( unsavedValue == null ) {
40-
if ( getter != null && templateInstanceAccess != null ) {
41-
// use the id value of a newly instantiated instance as the unsaved-value
42-
final Object defaultValue = getter.get( templateInstanceAccess.get() );
43-
return new IdentifierValue( defaultValue );
44-
}
45-
else if ( idJavaType instanceof PrimitiveJavaType<?> primitiveJavaType ) {
46-
return new IdentifierValue( primitiveJavaType.getDefaultValue() );
47-
}
48-
else {
49-
return IdentifierValue.NULL;
50-
}
37+
return switch ( bootIdMapping.getNullValueSemantic() ) {
38+
case null -> inferUnsavedIdentifierValue( idJavaType, getter, templateInstanceAccess );
39+
case UNDEFINED -> IdentifierValue.UNDEFINED;
40+
case NULL -> IdentifierValue.NULL;
41+
case ANY -> IdentifierValue.ANY;
42+
case NONE -> IdentifierValue.NONE;
43+
case VALUE -> new IdentifierValue( idJavaType.fromString( bootIdMapping.getNullValue() ) );
44+
default -> throw new IllegalArgumentException( "Illegal null-value semantic: "
45+
+ bootIdMapping.getNullValueSemantic() );
46+
};
47+
}
48+
49+
private static IdentifierValue inferUnsavedIdentifierValue(
50+
JavaType<?> idJavaType, Getter getter, Supplier<?> templateInstanceAccess) {
51+
if ( getter != null && templateInstanceAccess != null ) {
52+
// use the id value of a newly instantiated instance as the unsaved-value
53+
final Object defaultValue = getter.get( templateInstanceAccess.get() );
54+
return new IdentifierValue( defaultValue );
55+
}
56+
else if ( idJavaType instanceof PrimitiveJavaType<?> primitiveJavaType ) {
57+
return new IdentifierValue( primitiveJavaType.getDefaultValue() );
5158
}
5259
else {
53-
return switch ( unsavedValue ) {
54-
case "null" -> IdentifierValue.NULL;
55-
case "undefined" -> IdentifierValue.UNDEFINED;
56-
case "none" -> IdentifierValue.NONE;
57-
case "any" -> IdentifierValue.ANY;
58-
default -> new IdentifierValue( idJavaType.fromString( unsavedValue ) );
59-
};
60+
return IdentifierValue.NULL;
6061
}
6162
}
6263

@@ -72,31 +73,32 @@ public static <T> VersionValue getUnsavedVersionValue(
7273
VersionJavaType<T> versionJavaType,
7374
Getter getter,
7475
Supplier<?> templateInstanceAccess) {
75-
final String unsavedValue = bootVersionMapping.getNullValue();
76-
if ( unsavedValue == null ) {
77-
if ( getter != null && templateInstanceAccess != null ) {
78-
final Object defaultValue = getter.get( templateInstanceAccess.get() );
79-
// if the version of a newly instantiated object is null
80-
// or a negative number, use that value as the unsaved-value,
81-
// otherwise assume it's the initial version set by program
82-
return isNullInitialVersion( defaultValue )
83-
? new VersionValue( defaultValue )
84-
: VersionValue.UNDEFINED;
85-
}
86-
else {
87-
return VersionValue.UNDEFINED;
88-
}
76+
return switch ( bootVersionMapping.getNullValueSemantic() ) {
77+
case null -> inferUnsavedVersionValue( versionJavaType, getter, templateInstanceAccess );
78+
case UNDEFINED -> VersionValue.UNDEFINED;
79+
case NULL -> VersionValue.NULL;
80+
case NEGATIVE -> VersionValue.NEGATIVE;
81+
// this should not happen since the DTD prevents it
82+
case VALUE -> new VersionValue( versionJavaType.fromString( bootVersionMapping.getNullValue() ) );
83+
default -> throw new IllegalArgumentException( "Illegal null-value semantic: "
84+
+ bootVersionMapping.getNullValueSemantic() );
85+
};
86+
}
87+
88+
private static VersionValue inferUnsavedVersionValue(
89+
VersionJavaType<?> versionJavaType, Getter getter, Supplier<?> templateInstanceAccess) {
90+
if ( getter != null && templateInstanceAccess != null ) {
91+
final Object defaultValue = getter.get( templateInstanceAccess.get() );
92+
// if the version of a newly instantiated object is null
93+
// or a negative number, use that value as the unsaved-value,
94+
// otherwise assume it's the initial version set by program
95+
return isNullInitialVersion( defaultValue )
96+
? new VersionValue( defaultValue )
97+
: VersionValue.UNDEFINED;
8998
}
9099
else {
91-
// this should not happen since the DTD prevents it
92-
return switch ( unsavedValue ) {
93-
case "undefined" -> VersionValue.UNDEFINED;
94-
case "null" -> VersionValue.NULL;
95-
case "negative" -> VersionValue.NEGATIVE;
96-
default -> throw new MappingException( "Could not parse version unsaved-value: " + unsavedValue );
97-
};
100+
return VersionValue.UNDEFINED;
98101
}
99-
100102
}
101103

102104
private UnsavedValueFactory() {

hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,18 @@ public interface KeyValue extends Value {
2222

2323
boolean isCascadeDeleteEnabled();
2424

25+
enum NullValueSemantic { VALUE, NULL, NEGATIVE, UNDEFINED, NONE, ANY }
26+
27+
NullValueSemantic getNullValueSemantic();
28+
2529
String getNullValue();
2630

2731
boolean isUpdateable();
2832

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

hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public abstract class SimpleValue implements KeyValue {
9191
private boolean isNationalized;
9292
private boolean isLob;
9393

94+
private NullValueSemantic nullValueSemantic;
9495
private String nullValue;
9596

9697
private Table table;
@@ -410,8 +411,8 @@ public Generator createGenerator(
410411
final IdGeneratorCreationContext context =
411412
new IdGeneratorCreationContext( rootClass, property, defaults );
412413
final Generator generator = customIdGeneratorCreator.createGenerator( context );
413-
if ( generator.allowAssignedIdentifiers() && getNullValue() == null ) {
414-
setNullValue( "undefined" );
414+
if ( generator.allowAssignedIdentifiers() && nullValue == null ) {
415+
setNullValueUndefined();
415416
}
416417
return generator;
417418
}
@@ -449,17 +450,72 @@ public Table getTable() {
449450
return table;
450451
}
451452

453+
/**
454+
* The property or field value which indicates that field
455+
* or property has never been set.
456+
*
457+
* @see org.hibernate.engine.internal.UnsavedValueFactory
458+
* @see org.hibernate.engine.spi.IdentifierValue
459+
* @see org.hibernate.engine.spi.VersionValue
460+
*/
452461
@Override
453462
public String getNullValue() {
454463
return nullValue;
455464
}
456465

457466
/**
458-
* Sets the nullValue.
459-
* @param nullValue The nullValue to set
467+
* Set the property or field value indicating that field
468+
* or property has never been set.
469+
*
470+
* @see org.hibernate.engine.internal.UnsavedValueFactory
471+
* @see org.hibernate.engine.spi.IdentifierValue
472+
* @see org.hibernate.engine.spi.VersionValue
460473
*/
461474
public void setNullValue(String nullValue) {
462-
this.nullValue = nullValue;
475+
nullValueSemantic = switch (nullValue) {
476+
// magical values (legacy of hbm.xml)
477+
case "null" -> NullValueSemantic.NULL;
478+
case "none" -> NullValueSemantic.NONE;
479+
case "any" -> NullValueSemantic.ANY;
480+
case "undefined" -> NullValueSemantic.UNDEFINED;
481+
default -> NullValueSemantic.VALUE;
482+
};
483+
if ( nullValueSemantic == NullValueSemantic.VALUE ) {
484+
this.nullValue = nullValue;
485+
}
486+
}
487+
488+
/**
489+
* The rule for determining if the field or
490+
* property has been set.
491+
*
492+
* @see org.hibernate.engine.internal.UnsavedValueFactory
493+
*/
494+
public NullValueSemantic getNullValueSemantic() {
495+
return nullValueSemantic;
496+
}
497+
498+
/**
499+
* Specifies the rule for determining if the field or
500+
* property has been set.
501+
*
502+
* @see org.hibernate.engine.internal.UnsavedValueFactory
503+
*/
504+
public void setNullValueSemantic(NullValueSemantic nullValueSemantic) {
505+
this.nullValueSemantic = nullValueSemantic;
506+
}
507+
508+
/**
509+
* Specifies that there is no well-defined property or
510+
* field value indicating that field or property has never
511+
* been set.
512+
*
513+
* @see org.hibernate.engine.internal.UnsavedValueFactory
514+
* @see org.hibernate.engine.spi.IdentifierValue#UNDEFINED
515+
* @see org.hibernate.engine.spi.VersionValue#UNDEFINED
516+
*/
517+
public void setNullValueUndefined() {
518+
nullValueSemantic = NullValueSemantic.UNDEFINED;
463519
}
464520

465521
public String getForeignKeyName() {

0 commit comments

Comments
 (0)