naman2627 opened a new pull request, #6560:
URL: https://github.com/apache/fineract/pull/6560

   ## Problem
   `DataValidatorBuilder.validateForBooleanValue()` throws a 
`NullPointerException` when the value is null and `ignoreIfNull()` was not 
called, so validators that pass a null value through it fail with an unhandled 
exception instead of a validation error — e.g. `JobDetailDataValidator` 
(`{"active": null}` or `{"active": ""}`), which calls 
`.notBlank().validateForBooleanValue()`.
   
   ## Root cause
   The private `validateStringFor(...)` returned early for null only when 
`ignoreNullValue` was set; otherwise it proceeded to `this.value.toString()` 
(`DataValidatorBuilder.java:962`). If null had been intended as a validation 
error, the method would add to `dataValidationErrors`, as its non-null 
rejection path does, rather than throw an NPE — so the null case was simply 
unhandled. Skipping it matches the class's value-format checks (e.g. 
`validateCronExpression`, `inMinMaxRange`, `positiveAmount`), which leave 
missing-value reporting to `notNull()`/`notBlank()`; callers that require the 
field already chain `notBlank()` first, so reporting null here as well would 
duplicate that error.
   
   ## Fix
   Return early from `validateStringFor` whenever the value is null (one-line 
change). The only behavioural change is for a null value without 
`ignoreIfNull()`, which previously threw an NPE and is now a no-op; null with 
`ignoreIfNull()` and all non-null values behave exactly as before. 
`ignoreNullValue` remains in use by the other checks in the class.
   
   ## Tests
   Added `DataValidatorBuilderBooleanValueTest` (fineract-core) covering 
accepted boolean strings, rejection of a non-boolean value, a null value on its 
own, and `notBlank()` + `validateForBooleanValue()` on null (expects exactly 
one `cannot.be.blank` error). The two null cases fail on develop with the NPE 
above and pass with the fix.
   
   ## Verification
   - `./gradlew :fineract-core:test --no-parallel` — 413 tests, 0 failures, 0 
errors, 0 skipped.
   - `./gradlew spotlessApply --no-parallel` — no formatting changes beyond 
this PR.
   - **Before the fix, on a running server (observed):** against a local devRun 
instance built before this change, `PUT /v1/jobs/1` with `{"active": null}` 
returned **HTTP 500**, and with `{"active": ""}` returned **HTTP 500**.
   - **After the fix, on a running server: not yet confirmed.** That these 
requests now return HTTP 400 with the `cannot.be.blank` error is verified only 
at unit level by the test above; the running instance predates the fix.
   - **Not run:** the full `./gradlew build` (runs out of memory on my machine) 
and integration tests. The code-value (`isActive`) and entity-datatable-check 
(`systemDefined`) paths were not exercised on a running server.
   
   ## Related
   - Relates to FINERACT-2694 — same defect family (a queued validation error 
bypassed by a null dereference, producing a 500 instead of a 400), different 
call path (`.intValue()`/`fromInt()`, not `validateForBooleanValue()`).
   - FINERACT-1013 (closed "Not A Problem") argued this method is effectively a 
no-op because `extractBooleanNamed()` pre-parses via `Boolean.parseBoolean()`, 
so invalid strings never reach it. That doesn't apply here:
     - It only covers non-null strings: an explicit JSON `null` is a 
`JsonNull`, so `extractBooleanNamed()` returns null without parsing, and the 
null reaches `this.value.toString()`.
     - The job and entity-datatable-check validators use 
`extractStringNamed()`, not `extractBooleanNamed()`, so nothing pre-parses: a 
value like `"yes"` reaches the method and is rejected, so it is not dead code 
on these paths. (The new test confirms the method rejects `"yes"`; that it 
arrives unparsed on these paths is from reading the code.)
     - `extractStringNamed()` also returns null for `""` and whitespace-only 
values. **Observed:** `PUT /v1/jobs/1` with `{"active": ""}` returned **HTTP 
500** on a running pre-fix instance.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to