[
https://issues.apache.org/jira/browse/FINERACT-2315?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Peter Thua updated FINERACT-2315:
---------------------------------
Description:
{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/\|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:#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:#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{color}
was:
{noformat}
# SMS Campaign Reports API Returns 500 Internal Server Error
## Summary
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.
## Environment
- {}API Endpoint:{} `/fineract-provider/api/v1/sms/{id}/messageByStatus`
- {}Framework:{} Jersey with HK2 dependency injection
- {}Java Version:{} 21
## Steps to Reproduce
### Prerequisites
- Access to Fineract SMS API
- Valid SMS campaign ID
- API authentication credentials
### Reproduction Steps
1. {}Create or identify an existing SMS campaign{}
- Ensure the campaign has sent messages
- Note the campaign ID (e.g., `2`)
2. {}Make API request to retrieve campaign reports{}
```bash
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
```
Replace `id` with your actual campaign ID.
3. {}Sample query parameters:{}
- `status=100` (or any valid status code)
- `locale=en`
- `dateFormat=dd MMMM yyyy`
- `fromDate=01 June 2025` (adjust date as needed)
- `toDate=17 June 2025` (adjust date as needed)
4. {}Execute the request{}
- Use any HTTP client (Postman, curl, browser, etc.)
- Include necessary authentication headers
### Expected Result
API should return SMS message data filtered by the specified status and date
range.
### Actual Result
API returns a 500 Internal Server Error with the following response:
```json
{
"timestamp": "2025-06-17T12:06:20.745Z",
"status": 500,
"error": "Internal Server Error",
"path": "/fineract-provider/api/v1/sms/2/messageByStatus"
{color:#000000}}
```
## Error Details
### Server Console Error
```
org.glassfish.hk2.api.MultiException: A MultiException has 2 exceptions. They
are:
1. java.lang.NoSuchMethodException: Could not find a suitable constructor in
org.apache.fineract.infrastructure.sms.param.SmsRequestParam class.
2. java.lang.IllegalArgumentException: Errors were discovered while reifying
SystemDescriptor(...)
```
### Error Analysis
The error occurs in the following sequence:
1. Jersey receives the HTTP request with query parameters
2. Jersey attempts to create an instance of `SmsRequestParam` (annotated with
`@BeanParam`)
3. HK2 dependency injection container tries to instantiate the parameter class
4. HK2 fails to find a suitable constructor in the record-based
`SmsRequestParam` class
5. `NoSuchMethodException` is thrown, causing the 500 error
## Root Cause
### Technical Details
- {}Framework Incompatibility:{} Jersey uses HK2 for dependency injection,
which requires classes to have default constructors for instantiation
- {}Record Limitation:{} Java records only provide constructors that accept all
declared parameters; they do not have default (no-argument) constructors
- {}Parameter Binding Process:{} The `@BeanParam` annotation instructs Jersey
to:
1. Create an instance of the parameter class using dependency injection
2. Populate the instance fields using query parameter values
3. Pass the populated instance to the endpoint method
### Why Records Don't Work
Records are immutable data carriers that:
- Automatically generate constructors requiring all parameters
- Do not provide default constructors
- Cannot be instantiated without providing all field values upfront
This conflicts with HK2's instantiation process, which expects to create empty
instances first and then populate them through setter methods or field
injection.
## Solution Implemented
### Code Changes
Converted `SmsRequestParam` from a record to a regular class with:
{}Before (Record):{}
```java
public record SmsRequestParam(Long status, DateParam fromDate, DateParam
toDate, String locale, String rawDateFormat, Integer offset,
Integer limit, String orderBy, String sortOrder) {}
```
{}After (Regular Class):{}
```java
@Data
@NoArgsConstructor
public class SmsRequestParam {
@QueryParam("status")
private Long status;
@QueryParam("fromDate")
private DateParam fromDate;
@QueryParam("toDate")
private DateParam toDate;
@QueryParam("locale")
private String locale;
@QueryParam("dateFormat")
private String rawDateFormat;
@QueryParam("offset")
private Integer offset;
@QueryParam("limit")
private Integer limit;
@QueryParam("orderBy")
private String orderBy;
@QueryParam("sortOrder")
private String sortOrder;
{color:#000000}}
```
### How the Fix Works
1. {}Default Constructor:{} Allows HK2 to create an empty instance
2. {}Setter Methods:{} Enable Jersey to populate fields with query parameter
values
3. {}Field Annotations:{} `@QueryParam` annotations directly map HTTP
parameters to class fields
4. {}Dependency Injection:{} HK2 can now successfully instantiate and populate
the parameter object
## Verification
After implementing the fix:
1. The API endpoint successfully processes requests
2. Query parameters are correctly mapped to the parameter object
3. SMS campaign reports are returned as expected
4. No more 500 Internal Server Error responses
## Impact
- {}Severity:{} High - API endpoint completely non-functional
- {}Affected Users:{} All users attempting to retrieve SMS campaign reports
- {}Workaround:{} None available before fix implementation
## Related Issues
- Consider reviewing other record-based parameter classes in the codebase
- Evaluate compatibility of Java records with Jersey/HK2 framework combination
- Document best practices for parameter binding in the project{noformat}
> 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
> Priority: Major
> 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/\|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:#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:#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{color}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)