Peter Thua created FINERACT-2315:
------------------------------------

             Summary: Error Reading SMS Campaing Reports e.g. Pending or Sent 
SMS
                 Key: FINERACT-2315
                 URL: https://issues.apache.org/jira/browse/FINERACT-2315
             Project: Apache Fineract
          Issue Type: Bug
            Reporter: Peter Thua
         Attachments: image-2025-06-19-09-26-39-710.png

{color:#0000ff}# SMS Campaign Reports API Returns 500 Internal Server 
Error{color}

{color:#0000ff}## Summary{color}
{color:#000000}API endpoint for retrieving SMS campaign reports by status 
returns a 500 Internal Server Error due to HK2 dependency injection failure 
with record-based parameter classes.{color}

{color:#0000ff}## Environment{color}
{color:#0000ff}- {color}{color:#000000}**API Endpoint:**{color}{color:#000000} 
{color}{color:#001188}`/fineract-provider/api/v1/sms/\{id}/messageByStatus`{color}
{color:#0000ff}- {color}{color:#000000}**Framework:**{color}{color:#000000} 
Jersey with HK2 dependency injection{color}
{color:#0000ff}- {color}{color:#000000}**Java Version:**{color}{color:#000000} 
21{color}

{color:#0000ff}## Steps to Reproduce{color}

{color:#0000ff}### Prerequisites{color}
{color:#0000ff}- {color}{color:#000000}Access to Fineract SMS API{color}
{color:#0000ff}- {color}{color:#000000}Valid SMS campaign ID{color}
{color:#0000ff}- {color}{color:#000000}API authentication credentials{color}

{color:#0000ff}### Reproduction Steps{color}
{color:#0000ff}1. {color}{color:#000000}**Create or identify an existing SMS 
campaign**{color}
{color:#0000ff}   - {color}{color:#000000}Ensure the campaign has sent 
messages{color}
{color:#0000ff}   - {color}{color:#000000}Note the campaign ID (e.g., 
{color}{color:#001188}`2`{color}{color:#000000}){color}

{color:#0000ff}2. {color}{color:#000000}**Make API request to retrieve campaign 
reports**{color}
{color:#a31515}   ```bash{color}
{color:#000000}   GET 
https://localhost:8443/fineract-provider/api/v1/sms/\{{id}}/messageByStatus?status=100&locale=en&dateFormat=dd
 MMMM yyyy&fromDate=01 June 2025&toDate=17 June 2025{color}
{color:#000000}   {color}{color:#a31515}```{color}
{color:#000000}   {color}
{color:#000000}   Replace {color}{color:#001188}`\{{id}}`{color}{color:#000000} 
with your actual campaign ID.{color}

{color:#0000ff}3. {color}{color:#000000}**Sample query parameters:**{color}
{color:#0000ff}   - {color}{color:#001188}`status=100`{color}{color:#000000} 
(or any valid status code){color}
{color:#0000ff}   - {color}{color:#001188}`locale=en`{color}
{color:#0000ff}   - {color}{color:#001188}`dateFormat=dd MMMM yyyy`{color}
{color:#0000ff}   - {color}{color:#001188}`fromDate=01 June 
2025`{color}{color:#000000} (adjust date as needed){color}
{color:#0000ff}   - {color}{color:#001188}`toDate=17 June 
2025`{color}{color:#000000} (adjust date as needed){color}

{color:#0000ff}4. {color}{color:#000000}**Execute the request**{color}
{color:#0000ff}   - {color}{color:#000000}Use any HTTP client (Postman, curl, 
browser, etc.){color}
{color:#0000ff}   - {color}{color:#000000}Include necessary authentication 
headers{color}

{color:#0000ff}### Expected Result{color}
{color:#000000}API should return SMS message data filtered by the specified 
status and date range.{color}

{color:#0000ff}### Actual Result{color}
{color:#000000}API returns a 500 Internal Server Error with the following 
response:{color}

{color:#a31515}```json{color}
{color:#000000}{{color}
{color:#000000}  "timestamp": "2025-06-17T12:06:20.745Z",{color}
{color:#000000}  "status": 500,{color}
{color:#000000}  "error": "Internal Server Error",{color}
{color:#000000}  "path": 
"/fineract-provider/api/v1/sms/2/messageByStatus"{color}
{color:#000000}}{color}
{color:#a31515}```{color}

{color:#0000ff}## Error Details{color}

{color:#0000ff}### Server Console Error{color}
{color:#a31515}```{color}
{color:#001188}org.glassfish.hk2.api.MultiException: A MultiException has 2 
exceptions. They are:{color}
{color:#001188}1. java.lang.NoSuchMethodException: Could not find a suitable 
constructor in org.apache.fineract.infrastructure.sms.param.SmsRequestParam 
class.{color}
{color:#001188}2. java.lang.IllegalArgumentException: Errors were discovered 
while reifying SystemDescriptor(...){color}
{color:#a31515}```{color}

{color:#0000ff}### Error Analysis{color}
{color:#000000}The error occurs in the following sequence:{color}
{color:#0000ff}1. {color}{color:#000000}Jersey receives the HTTP request with 
query parameters{color}
{color:#0000ff}2. {color}{color:#000000}Jersey attempts to create an instance 
of {color}{color:#001188}`SmsRequestParam`{color}{color:#000000} (annotated 
with {color}{color:#001188}`@BeanParam`{color}{color:#000000}){color}
{color:#0000ff}3. {color}{color:#000000}HK2 dependency injection container 
tries to instantiate the parameter class{color}
{color:#0000ff}4. {color}{color:#000000}HK2 fails to find a suitable 
constructor in the record-based 
{color}{color:#001188}`SmsRequestParam`{color}{color:#000000} class{color}
{color:#0000ff}5. 
{color}{color:#001188}`NoSuchMethodException`{color}{color:#000000} is thrown, 
causing the 500 error{color}

{color:#0000ff}## Root Cause{color}

{color:#0000ff}### Technical Details{color}
{color:#0000ff}- {color}{color:#000000}**Framework 
Incompatibility:**{color}{color:#000000} Jersey uses HK2 for dependency 
injection, which requires classes to have default constructors for 
instantiation{color}
{color:#0000ff}- {color}{color:#000000}**Record 
Limitation:**{color}{color:#000000} Java records only provide constructors that 
accept all declared parameters; they do not have default (no-argument) 
constructors{color}
{color:#0000ff}- {color}{color:#000000}**Parameter Binding 
Process:**{color}{color:#000000} The 
{color}{color:#001188}`@BeanParam`{color}{color:#000000} annotation instructs 
Jersey to:{color}
{color:#0000ff}  1. {color}{color:#000000}Create an instance of the parameter 
class using dependency injection{color}
{color:#0000ff}  2. {color}{color:#000000}Populate the instance fields using 
query parameter values{color}
{color:#0000ff}  3. {color}{color:#000000}Pass the populated instance to the 
endpoint method{color}

{color:#0000ff}### Why Records Don't Work{color}
{color:#000000}Records are immutable data carriers that:{color}
{color:#0000ff}- {color}{color:#000000}Automatically generate constructors 
requiring all parameters{color}
{color:#0000ff}- {color}{color:#000000}Do not provide default 
constructors{color}
{color:#0000ff}- {color}{color:#000000}Cannot be instantiated without providing 
all field values upfront{color}

{color:#000000}This conflicts with HK2's instantiation process, which expects 
to create empty instances first and then populate them through setter methods 
or field injection.{color}

{color:#0000ff}## Solution Implemented{color}

{color:#0000ff}### Code Changes{color}
{color:#000000}Converted 
{color}{color:#001188}`SmsRequestParam`{color}{color:#000000} from a record to 
a regular class with:{color}

{color:#000000}**Before (Record):**{color}
{color:#a31515}```java{color}
{color:#0000ff}public{color}{color:#000000} 
{color}{color:#0000ff}record{color}{color:#000000} SmsRequestParam(Long status, 
DateParam fromDate, DateParam toDate, String locale, String rawDateFormat, 
Integer offset,{color}
{color:#000000}        Integer limit, String orderBy, String sortOrder) 
{}{color}
{color:#a31515}```{color}

{color:#000000}**After (Regular Class):**{color}
{color:#a31515}```java{color}
{color:#808080}@Data{color}
{color:#808080}@NoArgsConstructor{color}
{color:#0000ff}public{color}{color:#000000} 
{color}{color:#0000ff}class{color}{color:#000000} SmsRequestParam {{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"status"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} Long 
status;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"fromDate"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} 
DateParam fromDate;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"toDate"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} 
DateParam toDate;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"locale"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} String 
locale;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"dateFormat"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} String 
rawDateFormat;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"offset"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} Integer 
offset;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"limit"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} Integer 
limit;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"orderBy"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} String 
orderBy;{color}

{color:#000000}    
{color}{color:#808080}@QueryParam{color}{color:#000000}({color}{color:#a31515}"sortOrder"{color}{color:#000000}){color}
{color:#000000}    {color}{color:#0000ff}private{color}{color:#000000} String 
sortOrder;{color}
{color:#000000}}{color}
{color:#a31515}```{color}

{color:#0000ff}### How the Fix Works{color}
{color:#0000ff}1. {color}{color:#000000}**Default 
Constructor:**{color}{color:#000000} Allows HK2 to create an empty 
instance{color}
{color:#0000ff}2. {color}{color:#000000}**Setter 
Methods:**{color}{color:#000000} Enable Jersey to populate fields with query 
parameter values{color}
{color:#0000ff}3. {color}{color:#000000}**Field 
Annotations:**{color}{color:#000000} 
{color}{color:#001188}`@QueryParam`{color}{color:#000000} annotations directly 
map HTTP parameters to class fields{color}
{color:#0000ff}4. {color}{color:#000000}**Dependency 
Injection:**{color}{color:#000000} HK2 can now successfully instantiate and 
populate the parameter object{color}

{color:#0000ff}## Verification{color}
{color:#000000}After implementing the fix:{color}
{color:#0000ff}1. {color}{color:#000000}The API endpoint successfully processes 
requests{color}
{color:#0000ff}2. {color}{color:#000000}Query parameters are correctly mapped 
to the parameter object{color}
{color:#0000ff}3. {color}{color:#000000}SMS campaign reports are returned as 
expected{color}
{color:#0000ff}4. {color}{color:#000000}No more 500 Internal Server Error 
responses{color}

{color:#0000ff}## Impact{color}
{color:#0000ff}- {color}{color:#000000}**Severity:**{color}{color:#000000} High 
- API endpoint completely non-functional{color}
{color:#0000ff}- {color}{color:#000000}**Affected 
Users:**{color}{color:#000000} All users attempting to retrieve SMS campaign 
reports{color}
{color:#0000ff}- {color}{color:#000000}**Workaround:**{color}{color:#000000} 
None available before fix implementation{color}

{color:#0000ff}## Related Issues{color}
{color:#0000ff}- {color}{color:#000000}Consider reviewing other record-based 
parameter classes in the codebase{color}
{color:#0000ff}- {color}{color:#000000}Evaluate compatibility of Java records 
with Jersey/HK2 framework combination{color}
{color:#0000ff}- {color}{color:#000000}Document best practices for parameter 
binding in the project
!image-2025-06-19-09-26-39-710.png!
{color}



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

Reply via email to