Foo Developer created FINERACT-2863:
---------------------------------------

             Summary: Retrieving a savings account with template=true fails 
with NullPointerException on productOptions accountingRule
                 Key: FINERACT-2863
                 URL: https://issues.apache.org/jira/browse/FINERACT-2863
             Project: Apache Fineract
          Issue Type: Bug
          Components: Savings
            Reporter: Foo Developer
            Assignee: Foo Developer


h3. Steps to reproduce
# Create a savings product (any accounting rule), a client, and submit a 
savings account application for that client.
# Load the account with its template, as a UI does for the "modify application" 
form:

{code}GET 
/fineract-provider/api/v1/savingsaccounts/{accountId}?template=true&associations=charges
{code}

h3. Expected

HTTP 200 with the account, including {{productOptions}} for the product 
dropdown.

h3. Actual

The request fails while the response is serialized: a {{NullPointerException}} 
inside a bean getter, returned as a raw error (HTTP 400 on current {{develop}}, 
with the exception text as the body), so the account cannot be edited:

{code}Cannot invoke 
"org.apache.fineract.infrastructure.core.data.EnumOptionData.getValue()" 
because "this.accountingRule" is null
(through reference chain: 
SavingsAccountData["productOptions"]->ArrayList[0]->SavingsProductData["accrualBasedAccountingEnabled"])
{code}

{{GET /savingsaccounts/{accountId}}} without {{template=true}} works, and so 
does {{GET /savingsaccounts/template?clientId=...}} (that endpoint serializes 
through {{ToApiJsonSerializer}}). A successful {{PUT 
/savingsaccounts/{accountId}}} cannot be read back with {{template=true}} 
either.

h3. Root cause

With {{template=true}}, {{SavingsAccountTemplateReadPlatformServiceImpl}} fills 
{{productOptions}} from 
{{SavingsProductReadPlatformService.retrieveAllForLookup()}}, whose row mapper 
returns {{SavingsProductData.lookup(id, name)}}. That factory deliberately 
leaves every field except id and name {{null}}, including {{accountingRule}}.

{{SavingsAccountsApiResource.retrieveOne}} returns {{SavingsAccountData}} 
itself, so the JAX-RS Jackson provider serializes it and calls every public 
bean getter it finds. {{SavingsProductData.isCashBasedAccountingEnabled()}}, 
{{isAccrualBasedAccountingEnabled()}}, {{isUpfrontAccrualAccounting()}} and 
{{isPeriodicAccrualAccounting()}} are picked up as properties, and they 
dereference {{accountingRule}} without a null check. {{hasAccountingEnabled()}} 
and {{accountingRuleTypeId()}} have the same unguarded dereference.

h3. Proposed fix

Null-guard the {{accountingRule}}-dependent methods in {{SavingsProductData}} 
(fineract-core), treating a missing accounting rule as "no accounting": the 
{{is...}}/{{has...}} methods return {{false}} and {{accountingRuleTypeId()}} 
returns {{AccountingRuleType.NONE}}. Behaviour for products that do carry an 
accounting rule is unchanged.

h3. Test

A unit test {{SavingsProductDataTest}} covering a lookup-only instance (all 
methods return "no accounting", and Jackson serialization no longer throws) and 
an instance with an accounting rule (still evaluated).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to