[
https://issues.apache.org/jira/browse/FINERACT-2665?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Farooq Ayoade updated FINERACT-2665:
------------------------------------
Description:
h3. Observed behavior
Modifying a submitted-and-pending loan application via {{{}PUT
/fineract-provider/api/v1/loans/{loanId{}}}} — when the change triggers a
schedule recalculation (e.g. changing {{{}productId{}}}) and the request body
does not resend {{interestType}} — returns HTTP 500 with a raw NPE:
{{java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()"
because "selectedMethod" is null
at
org.apache.fineract.portfolio.loanproduct.domain.InterestMethod.fromInt(InterestMethod.java:45)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanApplicationTermsFrom(LoanScheduleAssembler.java:238)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanTerms(LoanScheduleAssembler.java:178)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanScheduleFrom(LoanScheduleAssembler.java:711)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformServiceImpl.calculateLoanSchedule(LoanScheduleCalculationPlatformServiceImpl.java:79)
at
org.apache.fineract.portfolio.loanaccount.service.LoanAssemblerImpl.updateFrom(LoanAssemblerImpl.java:866)
at
org.apache.fineract.portfolio.loanaccount.service.LoanApplicationWritePlatformServiceJpaRepositoryImpl.modifyApplication(LoanApplicationWritePlatformServiceJpaRepositoryImpl.java:277)}}
The same class of NPE occurs for {{amortizationType}} and
{{{}interestCalculationPeriodType{}}}, and a null {{repaymentEvery}} is
produced, when those overrides are enabled on the product and the field is
omitted.
h3. Expected behavior
"Allow overriding X" on a loan product means the override is {*}optional{*}.
When the modify request omits an override-enabled attribute, the schedule
should be (re)built using the *product's configured value* for that attribute —
exactly as it already does when the override is _not_ enabled — instead of
dereferencing a null and throwing.
h3. Steps to reproduce
# Have a loan product with one or more attribute overrides enabled — i.e. a
row in {{m_product_loan_configurable_attributes}} with {{interest_method_enum =
1}} (and/or {{{}amortization_method_enum{}}},
{{{}interest_calculated_in_period_enum{}}}, {{{}repay_every{}}}). A product
with *no* row also reproduces, because
{{LoanProductConfigurableAttributes.populateDefaultsForConfigurableAttributes()}}
defaults every flag to {{{}true{}}}.
# Create a loan application (Submitted and pending approval) on some product.
# {{{}PUT /fineract-provider/api/v1/loans/{loanId{}}}} changing {{productId}}
to an override-enabled product, with a minimal body that omits
{{{}interestType{}}}:
\{{ { "locale": "en", "dateFormat": "dd MMMM yyyy", "loanType": "individual",
"productId": <overrideEnabledId> }
}}
# Observe HTTP 500 and the NPE above. (Re-sending the loan's _current_ product
is a no-op — {{{}changes:{}{{}}}}, no recalculation — so it appears to "work";
the failure only manifests once a real change forces the schedule rebuild.)
h3. Root cause
{{LoanScheduleAssembler.assembleLoanApplicationTermsFrom(...)}} reads each
override-gated attribute from the request JSON when the product allows
overriding it, but passes the (possibly {{{}null{}}}) value straight into
{{{}XxxMethod.fromInt(...){}}}:
final Boolean allowOverridingInterestMethod =
loanProduct.getLoanConfigurableAttributes().getInterestMethodBoolean();
final Integer interestType =
this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
// null on modify when omitted
final InterestMethod interestMethod = allowOverridingInterestMethod
? InterestMethod.fromInt(interestType) // line 238 — fromInt(null) →
NPE
: loanProduct.getLoanProductRelatedDetail().getInterestMethod();
{{}}
was:
h3. Observed behavior
Modifying a submitted-and-pending loan application via {{PUT
/fineract-provider/api/v1/loans/\{loanId}}} — when the change triggers a
schedule recalculation (e.g. changing {{{}productId{}}}) and the request body
does not resend {{interestType}} — returns HTTP 500 with a raw NPE:
!http://localhost:63343/markdownPreview/1998094097/custom-guide/core-tickets!
{{java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()"
because "selectedMethod" is null
at
org.apache.fineract.portfolio.loanproduct.domain.InterestMethod.fromInt(InterestMethod.java:45)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanApplicationTermsFrom(LoanScheduleAssembler.java:238)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanTerms(LoanScheduleAssembler.java:178)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanScheduleFrom(LoanScheduleAssembler.java:711)
at
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformServiceImpl.calculateLoanSchedule(LoanScheduleCalculationPlatformServiceImpl.java:79)
at
org.apache.fineract.portfolio.loanaccount.service.LoanAssemblerImpl.updateFrom(LoanAssemblerImpl.java:866)
at
org.apache.fineract.portfolio.loanaccount.service.LoanApplicationWritePlatformServiceJpaRepositoryImpl.modifyApplication(LoanApplicationWritePlatformServiceJpaRepositoryImpl.java:277)}}
The same class of NPE occurs for {{amortizationType}} and
{{{}interestCalculationPeriodType{}}}, and a null {{repaymentEvery}} is
produced, when those overrides are enabled on the product and the field is
omitted.
h3. Expected behavior
"Allow overriding X" on a loan product means the override is {*}optional{*}.
When the modify request omits an override-enabled attribute, the schedule
should be (re)built using the *product's configured value* for that attribute —
exactly as it already does when the override is _not_ enabled — instead of
dereferencing a null and throwing.
h3. Steps to reproduce
# Have a loan product with one or more attribute overrides enabled — i.e. a
row in {{m_product_loan_configurable_attributes}} with {{interest_method_enum =
1}} (and/or {{{}amortization_method_enum{}}},
{{{}interest_calculated_in_period_enum{}}}, {{{}repay_every{}}}). A product
with *no* row also reproduces, because
{{LoanProductConfigurableAttributes.populateDefaultsForConfigurableAttributes()}}
defaults every flag to {{{}true{}}}.
# Create a loan application (Submitted and pending approval) on some product.
# {{PUT /fineract-provider/api/v1/loans/\{loanId}}} changing {{productId}} to
an override-enabled product, with a minimal body that omits
{{{}interestType{}}}:
{{{ "locale": "en", "dateFormat": "dd MMMM yyyy", "loanType": "individual",
"productId": <overrideEnabledId> }}}
# Observe HTTP 500 and the NPE above. (Re-sending the loan's _current_ product
is a no-op — {{{}changes:{}{}}}, no recalculation — so it appears to "work";
the failure only manifests once a real change forces the schedule rebuild.)
h3. Root cause
{{LoanScheduleAssembler.assembleLoanApplicationTermsFrom(...)}} reads each
override-gated attribute from the request JSON when the product allows
overriding it, but passes the (possibly {{{}null{}}}) value straight into
{{{}XxxMethod.fromInt(...){}}}:
final Boolean allowOverridingInterestMethod =
loanProduct.getLoanConfigurableAttributes().getInterestMethodBoolean();
final Integer interestType =
this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
// null on modify when omitted
final InterestMethod interestMethod = allowOverridingInterestMethod
? InterestMethod.fromInt(interestType) // line 238 — fromInt(null) →
NPE
: loanProduct.getLoanProductRelatedDetail().getInterestMethod();
{{}}
> PUT /loans/{loanId} (modify loan application) fails with a
> NullPointerException (HTTP 500) when a loan product allows attribute
> overrides but the request omits the attribute
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: FINERACT-2665
> URL: https://issues.apache.org/jira/browse/FINERACT-2665
> Project: Apache Fineract
> Issue Type: Bug
> Components: Loan
> Reporter: Farooq Ayoade
> Priority: Minor
> Labels: bug, loan
>
> h3. Observed behavior
> Modifying a submitted-and-pending loan application via {{{}PUT
> /fineract-provider/api/v1/loans/{loanId{}}}} — when the change triggers a
> schedule recalculation (e.g. changing {{{}productId{}}}) and the request body
> does not resend {{interestType}} — returns HTTP 500 with a raw NPE:
>
>
> {{java.lang.NullPointerException: Cannot invoke
> "java.lang.Integer.intValue()" because "selectedMethod" is null
> at
> org.apache.fineract.portfolio.loanproduct.domain.InterestMethod.fromInt(InterestMethod.java:45)
> at
> org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanApplicationTermsFrom(LoanScheduleAssembler.java:238)
> at
> org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanTerms(LoanScheduleAssembler.java:178)
> at
> org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler.assembleLoanScheduleFrom(LoanScheduleAssembler.java:711)
> at
> org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformServiceImpl.calculateLoanSchedule(LoanScheduleCalculationPlatformServiceImpl.java:79)
> at
> org.apache.fineract.portfolio.loanaccount.service.LoanAssemblerImpl.updateFrom(LoanAssemblerImpl.java:866)
> at
> org.apache.fineract.portfolio.loanaccount.service.LoanApplicationWritePlatformServiceJpaRepositoryImpl.modifyApplication(LoanApplicationWritePlatformServiceJpaRepositoryImpl.java:277)}}
> The same class of NPE occurs for {{amortizationType}} and
> {{{}interestCalculationPeriodType{}}}, and a null {{repaymentEvery}} is
> produced, when those overrides are enabled on the product and the field is
> omitted.
> h3. Expected behavior
> "Allow overriding X" on a loan product means the override is {*}optional{*}.
> When the modify request omits an override-enabled attribute, the schedule
> should be (re)built using the *product's configured value* for that attribute
> — exactly as it already does when the override is _not_ enabled — instead of
> dereferencing a null and throwing.
> h3. Steps to reproduce
> # Have a loan product with one or more attribute overrides enabled — i.e. a
> row in {{m_product_loan_configurable_attributes}} with {{interest_method_enum
> = 1}} (and/or {{{}amortization_method_enum{}}},
> {{{}interest_calculated_in_period_enum{}}}, {{{}repay_every{}}}). A product
> with *no* row also reproduces, because
> {{LoanProductConfigurableAttributes.populateDefaultsForConfigurableAttributes()}}
> defaults every flag to {{{}true{}}}.
> # Create a loan application (Submitted and pending approval) on some product.
> # {{{}PUT /fineract-provider/api/v1/loans/{loanId{}}}} changing
> {{productId}} to an override-enabled product, with a minimal body that omits
> {{{}interestType{}}}:
> \{{ { "locale": "en", "dateFormat": "dd MMMM yyyy", "loanType":
> "individual", "productId": <overrideEnabledId> }
> }}
> # Observe HTTP 500 and the NPE above. (Re-sending the loan's _current_
> product is a no-op — {{{}changes:{}{{}}}}, no recalculation — so it appears
> to "work"; the failure only manifests once a real change forces the schedule
> rebuild.)
> h3. Root cause
> {{LoanScheduleAssembler.assembleLoanApplicationTermsFrom(...)}} reads each
> override-gated attribute from the request JSON when the product allows
> overriding it, but passes the (possibly {{{}null{}}}) value straight into
> {{{}XxxMethod.fromInt(...){}}}:
> final Boolean allowOverridingInterestMethod =
> loanProduct.getLoanConfigurableAttributes().getInterestMethodBoolean();
> final Integer interestType =
> this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType",
> element); // null on modify when omitted
> final InterestMethod interestMethod = allowOverridingInterestMethod
> ? InterestMethod.fromInt(interestType) // line 238 — fromInt(null)
> → NPE
> : loanProduct.getLoanProductRelatedDetail().getInterestMethod();
> {{}}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)