Naman Rathi created FINERACT-2884:
-------------------------------------
Summary: DataValidatorBuilder.validateForBooleanValue() throws
NullPointerException when value is null and ignoreIfNull() is not set
Key: FINERACT-2884
URL: https://issues.apache.org/jira/browse/FINERACT-2884
Project: Apache Fineract
Issue Type: Bug
Affects Versions: 1.16.0
Reporter: Naman Rathi
DataValidatorBuilder.validateForBooleanValue() delegates to the private
validateStringFor(...). That method only returns early for a null value when
ignoreIfNull() was called. Otherwise it goes on to call this.value.toString()
and throws a NullPointerException. The class's value-format checks (e.g.
validateCronExpression, inMinMaxRange, positiveAmount) skip null and leave
missing-value reporting to notNull()/notBlank().
Observed in a unit test on develop (386ee1523f):
java.lang.NullPointerException: Cannot invoke "Object.toString()" because
"this.value" is null
at
org.apache.fineract.infrastructure.core.data.DataValidatorBuilder.validateStringFor(DataValidatorBuilder.java:962)
at
org.apache.fineract.infrastructure.core.data.DataValidatorBuilder.validateForBooleanValue(DataValidatorBuilder.java:978)
h3. Affected callers
*Jobs (reproduced on a running server).* Against a locally running Fineract
instance (devRun, pre-fix build), PUT /v1/jobs/{jobId}:
* {"active": null} returns HTTP 500 Internal Server Error (observed).
* {"active": ""} returns HTTP 500 Internal Server Error (observed).
JobDetailDataValidator reads the value with extractStringNamed(), which returns
null for both inputs. It then calls .notBlank().validateForBooleanValue():
notBlank() records the "cannot.be.blank" error, and the NPE is thrown before
that error can be returned as an HTTP 400.
*Code values and entity datatable checks (from reading the code, not reproduced
against a running server).* An explicit JSON null makes the extractor return
null, and the validator then throws.
* Code value create/update with {"isActive": null}
(CodeValueCommandFromApiJsonDeserializer).
* Entity datatable check create with {"systemDefined": null}
(EntityDatatableChecksDataValidator).
h3. Relation to FINERACT-1013
FINERACT-1013 (closed as "Not A Problem", Dec 2025) was also about
validateForBooleanValue(). It was closed because extractBooleanNamed()
pre-parses the value via Boolean.parseBoolean(), so invalid strings never reach
the method. That reasoning doesn't hold here, for three reasons:
* It only covers non-null strings. An explicit JSON null is a JsonNull, not a
JsonPrimitive, so extractBooleanNamed() returns null without parsing anything.
The null reaches validateForBooleanValue() and fails at this.value.toString().
* Two of the three callers don't use extractBooleanNamed() at all.
JobDetailDataValidator and EntityDatatableChecksDataValidator use
extractStringNamed(), so nothing pre-parses the value. A non-boolean value such
as "yes" reaches the method and is rejected with value.should.true.or.false.
The method is not dead code on these paths. A new unit test confirms the method
rejects "yes"; that the value arrives there unparsed comes from reading the
code.
* Empty strings take the same route. extractStringNamed() also returns null for
"" and whitespace-only values. This is observed on the jobs path: PUT
/v1/jobs/{jobId} with {"active": ""} returned HTTP 500 on a running pre-fix
instance.
h3. Expected
A null value is skipped by validateForBooleanValue(), the same way the other
value-format checks handle null, so callers get their normal validation errors
(HTTP 400) instead of an NPE.
h3. Related issues
Relates to FINERACT-2694: same defect family (a queued DataValidatorBuilder
validation error is bypassed by a null dereference, giving a 500 instead of a
400), but a different call path (.intValue()/fromInt(), not
validateForBooleanValue()).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)