Skip to content

Commit aefab46

Browse files
committed
tiny cleanups in Nullability
1 parent 2e192ae commit aefab46

File tree

1 file changed

+47
-35
lines changed

1 file changed

+47
-35
lines changed

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

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
import static org.hibernate.internal.util.StringHelper.qualify;
2323

2424
/**
25-
* Implements the algorithm for validating property values for illegal null values
25+
* Implements the algorithm for validating property values for illegal null values.
26+
* <p>
27+
* For example, a field or property does not accept null values if it is mapped
28+
* {@link jakarta.persistence.Basic#optional @Basic(optional=false)}.
2629
*
2730
* @author Gavin King
2831
*/
@@ -81,8 +84,8 @@ public void checkNullability(
8184
*/
8285
public void checkNullability(final Object[] values, final EntityPersister persister) {
8386

84-
// Typically when Bean Validation is on, we don't want to validate null values
85-
// at the Hibernate Core level. Hence, the checkNullability setting.
87+
// Typically, when Bean Validation is present, we don't validate
88+
// not-null values here. Hence, the checkNullability setting.
8689
if ( checkNullability ) {
8790
// Algorithm:
8891
// Check for any level one nullability breaks
@@ -91,51 +94,59 @@ public void checkNullability(final Object[] values, final EntityPersister persis
9194
// Look at Collections containing components to
9295
// recursively check next level of nullability breaks
9396
//
94-
// In the previous implementation, not-null stuffs where checked
95-
// filtering by level one only updatable
96-
// or insertable columns. So setting a subcomponent as update="false"
97-
// has no effect on not-null check if the main component had good checkability
97+
// In the previous implementation, not-null stuff was checked
98+
// filtering by level one only updatable or insertable columns.
99+
// So setting a subcomponent as update="false" has no effect on
100+
// not-null check if the main component had good checkability
98101
// In this implementation, we keep this feature.
99-
// However, I never see any documentation mentioning that, but it's for
100-
// sure a limitation.
102+
// However, I never see any documentation mentioning that, but
103+
// it's for sure a limitation.
101104

102105
final boolean[] nullability = persister.getPropertyNullability();
103-
final boolean[] checkability = checkType == NullabilityCheckType.CREATE
104-
? persister.getPropertyInsertability()
105-
: persister.getPropertyUpdateability();
106+
final boolean[] checkability = getCheckability( persister );
106107
final Type[] propertyTypes = persister.getPropertyTypes();
107108
final Generator[] generators = persister.getEntityMetamodel().getGenerators();
108109
for ( int i = 0; i < values.length; i++ ) {
109110
if ( checkability[i]
110-
&& values[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY
111+
&& !unfetched( values[i] )
111112
&& !generated( generators[i] ) ) {
112113
final Object value = values[i];
113-
if ( !nullability[i] && value == null ) {
114-
//check basic level one nullability
115-
throw new PropertyValueException(
116-
"not-null property references a null or transient value",
117-
persister.getEntityName(),
118-
persister.getPropertyNames()[i]
114+
if ( value == null ) {
115+
if ( !nullability[i] ) {
116+
// check basic level-one nullability
117+
throw new PropertyValueException(
118+
"not-null property references a null or transient value",
119+
persister.getEntityName(),
120+
persister.getPropertyNames()[i]
119121
);
120-
122+
}
121123
}
122-
else if ( value != null ) {
123-
//values is not null and is checkable, we'll look deeper
124+
else {
125+
// values is not null and is checkable, we'll look deeper
124126
final String breakProperties = checkSubElementsNullability( propertyTypes[i], value );
125127
if ( breakProperties != null ) {
126128
throw new PropertyValueException(
127-
"not-null property references a null or transient value",
128-
persister.getEntityName(),
129-
qualify( persister.getPropertyNames()[i], breakProperties )
129+
"not-null property references a null or transient value",
130+
persister.getEntityName(),
131+
qualify( persister.getPropertyNames()[i], breakProperties )
130132
);
131133
}
132-
133134
}
134135
}
135136
}
136137
}
137138
}
138139

140+
private boolean[] getCheckability(EntityPersister persister) {
141+
return checkType == NullabilityCheckType.CREATE
142+
? persister.getPropertyInsertability()
143+
: persister.getPropertyUpdateability();
144+
}
145+
146+
private static boolean unfetched(Object value) {
147+
return value == LazyPropertyInitializer.UNFETCHED_PROPERTY;
148+
}
149+
139150
private static boolean generated(Generator generator) {
140151
return generator != null && generator.generatesSometimes();
141152
}
@@ -190,35 +201,36 @@ else if ( propertyType instanceof CollectionType collectionType ) {
190201
* @throws HibernateException error while getting subcomponent values
191202
*/
192203
private String checkComponentNullability(Object composite, CompositeType compositeType) {
193-
// IMPL NOTE : we currently skip checking "any" and "many to any" mappings.
204+
// IMPL NOTE: we currently skip checking "any" and "many-to-any" mappings.
194205
//
195-
// This is not the best solution. But atm there is a mismatch between AnyType#getPropertyNullability
196-
// and the fact that cascaded-saves for "many to any" mappings are not performed until after this nullability
197-
// check. So the nullability check fails for transient entity elements with generated identifiers because
198-
// the identifier is not yet generated/assigned (is null)
206+
// This is not the best solution. But there's a mismatch between AnyType.getPropertyNullability()
207+
// and the fact that cascaded-saves for "many-to-any" mappings are not performed until after this
208+
// nullability check. So the nullability check fails for transient entity elements with generated
209+
// identifiers because the identifier is not yet generated/assigned (is null).
199210
//
200-
// The more correct fix would be to cascade saves of the many-to-any elements before the Nullability checking
211+
// The fix would be to cascade saves of the many-to-any elements before Nullability checking.
201212

202213
if ( compositeType instanceof AnyType ) {
203214
return null;
204215
}
205216
else {
206217
final boolean[] nullability = compositeType.getPropertyNullability();
207218
if ( nullability != null ) {
208-
//do the test
219+
// do the test
209220
final Object[] values = compositeType.getPropertyValues( composite, session );
210221
final Type[] propertyTypes = compositeType.getSubtypes();
222+
final String[] propertyNames = compositeType.getPropertyNames();
211223
for ( int i = 0; i < values.length; i++ ) {
212224
final Object value = values[i];
213225
if ( value == null ) {
214226
if ( !nullability[i] ) {
215-
return compositeType.getPropertyNames()[i];
227+
return propertyNames[i];
216228
}
217229
}
218230
else {
219231
final String breakProperties = checkSubElementsNullability( propertyTypes[i], value );
220232
if ( breakProperties != null ) {
221-
return qualify( compositeType.getPropertyNames()[i], breakProperties );
233+
return qualify( propertyNames[i], breakProperties );
222234
}
223235
}
224236
}

0 commit comments

Comments
 (0)