[ 
https://issues.apache.org/jira/browse/FINERACT-2884?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Naman Rathi updated FINERACT-2884:
----------------------------------
    Description: 
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)

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).

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.

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.

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()).

  was:
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()).


> 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
>            Priority: Major
>
> 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)
> 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).
> 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.
> 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.
> 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)

Reply via email to