Foo Developer created FINERACT-2865:
---------------------------------------
Summary: Reading a group's calendars fails with HTTP 500 when it
has a non-repeating calendar
Key: FINERACT-2865
URL: https://issues.apache.org/jira/browse/FINERACT-2865
Project: Apache Fineract
Issue Type: Bug
Components: Groups
Reporter: Foo Developer
Assignee: Foo Developer
h3. Summary
Reading calendars fails with a {{NullPointerException}} as soon as the entity
has a *non-repeating* calendar. A non-repeating calendar is stored with
{{recurrence = NULL}} (by design, see {{Calendar}} constructor and
{{Calendar.update}}), but the row mappers in
{{CalendarReadPlatformServiceImpl}} pass that null rule straight into
{{CalendarUtils}}, which hands it to ical4j's {{RRule}} parser.
h3. Steps to reproduce (stock Fineract)
# Create a group: {{POST /v1/groups}} (any office, active).
# Add a non-repeating, non-collection calendar to it:
{code:json}POST /v1/groups/{groupId}/calendars
{ "title": "One-off meeting", "typeId": 4, "repeating": false, "startDate": "28
September 2026", "locale": "en", "dateFormat": "dd MMMM yyyy" }
{code}
# Read it back: {{GET /v1/groups/{groupId}/calendars/{calendarId}}}, or list
{{GET /v1/groups/{groupId}/calendars}}. The same mapper also backs other
calendar reads, e.g. {{GET
/v1/loans/template?templateType=jlgbulk&groupId={groupId}}}.
h3. Expected
HTTP 200. The calendar is returned with {{repeating: false}}, no {{frequency}}
/ {{repeatsOnDay}} / {{repeatsOnNthDayOfMonth}} and {{interval: 0}}, the same
defaults already used for a rule that cannot be parsed.
h3. Actual
The request fails with HTTP 500 ({{Internal Server Error}}); the server log
shows a {{NullPointerException}} ({{Cannot invoke "String.split(String)"
because "aValue" is null}}) thrown from {{CalendarUtils.getICalRecur}} (ical4j
{{RRule}} with a null rule string), reached from
{{CalendarReadPlatformServiceImpl$CalendarDataMapper.mapRow}}.
h3. Root cause
Both {{CalendarDataMapper}} and {{CalendarDataFromHistoryMapper}} call
{{CalendarUtils.getFrequency}}, {{getInterval}}, {{getRepeatsOnDay}},
{{getRepeatsOnNthDayOfMonth}} and {{getMonthOnDay}} unconditionally. Each of
them parses the rule with {{getICalRecur(recurrence)}}, which cannot handle
{{null}}. The neighbouring {{humanReadable}} computation in the same mappers
already guards with {{recurrence != null}}; the other five calls do not.
h3. Proposed fix
Guard those five calls with {{recurrence != null}} in both mappers and fall
back to {{CalendarFrequencyType.INVALID}}, {{0}},
{{CalendarWeekDaysType.INVALID}}, {{NthDayType.INVALID}} and {{null}} (which
{{CalendarEnumerations}} already renders as "no value"). Repeating calendars
are unaffected.
h3. Test
A unit test {{CalendarReadPlatformServiceImplTest}} maps a non-repeating
calendar row (null recurrence) through {{retrieveCalendar}} and checks the
defaults, plus a repeating row to show the rule is still parsed.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)