22
22
import static org .hibernate .internal .util .StringHelper .qualify ;
23
23
24
24
/**
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)}.
26
29
*
27
30
* @author Gavin King
28
31
*/
@@ -81,8 +84,8 @@ public void checkNullability(
81
84
*/
82
85
public void checkNullability (final Object [] values , final EntityPersister persister ) {
83
86
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.
86
89
if ( checkNullability ) {
87
90
// Algorithm:
88
91
// Check for any level one nullability breaks
@@ -91,51 +94,59 @@ public void checkNullability(final Object[] values, final EntityPersister persis
91
94
// Look at Collections containing components to
92
95
// recursively check next level of nullability breaks
93
96
//
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
98
101
// 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.
101
104
102
105
final boolean [] nullability = persister .getPropertyNullability ();
103
- final boolean [] checkability = checkType == NullabilityCheckType .CREATE
104
- ? persister .getPropertyInsertability ()
105
- : persister .getPropertyUpdateability ();
106
+ final boolean [] checkability = getCheckability ( persister );
106
107
final Type [] propertyTypes = persister .getPropertyTypes ();
107
108
final Generator [] generators = persister .getEntityMetamodel ().getGenerators ();
108
109
for ( int i = 0 ; i < values .length ; i ++ ) {
109
110
if ( checkability [i ]
110
- && values [i ] != LazyPropertyInitializer . UNFETCHED_PROPERTY
111
+ && ! unfetched ( values [i ] )
111
112
&& !generated ( generators [i ] ) ) {
112
113
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 ]
119
121
);
120
-
122
+ }
121
123
}
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
124
126
final String breakProperties = checkSubElementsNullability ( propertyTypes [i ], value );
125
127
if ( breakProperties != null ) {
126
128
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 )
130
132
);
131
133
}
132
-
133
134
}
134
135
}
135
136
}
136
137
}
137
138
}
138
139
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
+
139
150
private static boolean generated (Generator generator ) {
140
151
return generator != null && generator .generatesSometimes ();
141
152
}
@@ -190,35 +201,36 @@ else if ( propertyType instanceof CollectionType collectionType ) {
190
201
* @throws HibernateException error while getting subcomponent values
191
202
*/
192
203
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.
194
205
//
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).
199
210
//
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.
201
212
202
213
if ( compositeType instanceof AnyType ) {
203
214
return null ;
204
215
}
205
216
else {
206
217
final boolean [] nullability = compositeType .getPropertyNullability ();
207
218
if ( nullability != null ) {
208
- //do the test
219
+ // do the test
209
220
final Object [] values = compositeType .getPropertyValues ( composite , session );
210
221
final Type [] propertyTypes = compositeType .getSubtypes ();
222
+ final String [] propertyNames = compositeType .getPropertyNames ();
211
223
for ( int i = 0 ; i < values .length ; i ++ ) {
212
224
final Object value = values [i ];
213
225
if ( value == null ) {
214
226
if ( !nullability [i ] ) {
215
- return compositeType . getPropertyNames () [i ];
227
+ return propertyNames [i ];
216
228
}
217
229
}
218
230
else {
219
231
final String breakProperties = checkSubElementsNullability ( propertyTypes [i ], value );
220
232
if ( breakProperties != null ) {
221
- return qualify ( compositeType . getPropertyNames () [i ], breakProperties );
233
+ return qualify ( propertyNames [i ], breakProperties );
222
234
}
223
235
}
224
236
}
0 commit comments