Skip to content

fix(formatters): pin Locale.ROOT on every COBOL date formatter#42

Merged
a2chang merged 2 commits intomainfrom
polish/pin-locale-root
May 1, 2026
Merged

fix(formatters): pin Locale.ROOT on every COBOL date formatter#42
a2chang merged 2 commits intomainfrom
polish/pin-locale-root

Conversation

@a2chang
Copy link
Copy Markdown
Contributor

@a2chang a2chang commented May 1, 2026

Closes #16.

What

DateTimeFormatter.ofPattern(...) without an explicit locale uses the JVM default locale, which can emit non-ASCII digits (e.g. Eastern Arabic) under some locales. Any such output going into PROCTRAN.DESCRIPTION would corrupt the COBOL-shaped audit-trail text.

Audit of the codebase found seven formatters still missing a pinned locale. All seven now use Locale.ROOT:

Repository:

  • CreaccRepository.COBOL_DATE_FORMATTER (ddMMyyyy)
  • CrecustRepository.PROCTRAN_DOB_FORMATTER (dd/MM/yyyy)

Service:

  • CrecustService.COBOL_DATE_FORMATTER (ddMMuuuu, used to parse the request DOB; locale-independent for digits but pinned for consistency)

Controllers:

  • InqacccuController.COBOL_DATE_FORMATTER (ddMMyyyy)
  • CrecustController.COBOL_DATE_FORMATTER (ddMMyyyy)
  • CreaccController.COBOL_DATE_FORMATTER (ddMMyyyy)
  • InqaccController.COBOL_DATE_FORMATTER (ddMMyyyy)

The formatters in UpdcustRepository, DelcusRepository, DelaccRepository, DelcusController, DelaccController, UpdaccController, UpdcustController already pinned Locale.ROOT and are unchanged.

Tests

Behaviour is unchanged when running under an ASCII-digit locale (the CI default), so existing tests still cover the pre/post behaviour. Local ./mvnw verify green: 198/198.

augment review

Closes #16.

DateTimeFormatter.ofPattern(...) without an explicit locale uses the
JVM default locale, which can emit non-ASCII digits under some
locales. Any such output going into PROCTRAN.DESCRIPTION would corrupt
the COBOL-shaped audit-trail text.

Audit of the codebase found seven formatters still missing a pinned
locale. All seven now use Locale.ROOT:

- CreaccRepository.COBOL_DATE_FORMATTER (ddMMyyyy)
- CrecustRepository.PROCTRAN_DOB_FORMATTER (dd/MM/yyyy)
- CrecustService.COBOL_DATE_FORMATTER (ddMMuuuu, used for parsing)
- InqacccuController.COBOL_DATE_FORMATTER (ddMMyyyy)
- CrecustController.COBOL_DATE_FORMATTER (ddMMyyyy)
- CreaccController.COBOL_DATE_FORMATTER (ddMMyyyy)
- InqaccController.COBOL_DATE_FORMATTER (ddMMyyyy)

The formatters in UpdcustRepository, DelcusRepository, DelaccRepository,
DelcusController, DelaccController, UpdaccController, UpdcustController
already pinned Locale.ROOT and are unchanged.
Copy link
Copy Markdown

@augment-app-staging augment-app-staging Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.


private static final DateTimeFormatter COBOL_DATE_FORMATTER =
DateTimeFormatter.ofPattern("ddMMuuuu").withResolverStyle(ResolverStyle.STRICT);
DateTimeFormatter.ofPattern("ddMMuuuu", Locale.ROOT).withResolverStyle(ResolverStyle.STRICT);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since COBOL_DATE_FORMATTER is now pinned to Locale.ROOT, parseDateOfBirth’s String.format("%08d", cobolDate) can still produce locale-specific digits under some JVM locales, which would then fail to parse against the ROOT formatter.
This could change behavior in non-ASCII-digit locales (DOBs that previously parsed may now be rejected).

Severity: high

🤖 Was this useful? React with 👍 or 👎

private static final String GLOBAL_CONTROL_ID = "GLOBAL";
private static final DateTimeFormatter PROCTRAN_DOB_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
private static final DateTimeFormatter PROCTRAN_DOB_FORMATTER =
DateTimeFormatter.ofPattern("dd/MM/yyyy", Locale.ROOT);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with PROCTRAN_DOB_FORMATTER pinned to Locale.ROOT, toDescription still uses String.format(...) without an explicit locale for the customer number, which can emit non-ASCII digits under some JVM locales.
That means PROCTRAN.DESCRIPTION could still be corrupted in the same scenarios this PR is trying to prevent.

Severity: high

🤖 Was this useful? React with 👍 or 👎

Round-1 review on #42 caught two String.format calls that still relied
on the JVM default locale, undermining the formatter pinning:

1. CrecustRepository.toDescription used String.format(\%010d\, ...)
   and String.format(\%-14.14s\, ...) for the customer-number and
   name slots of PROCTRAN.DESCRIPTION. Under a non-ASCII-digit JVM
   locale, the customer number could be emitted with non-ASCII digits,
   corrupting the COBOL-shaped audit-trail text \u2014 the very thing the
   PROCTRAN_DOB_FORMATTER pinning was meant to prevent.

2. CrecustService.parseDateOfBirth used String.format(\%08d\, ...) to
   normalize the int DOB before parsing it through the now-ROOT-pinned
   COBOL_DATE_FORMATTER. Under a non-ASCII-digit locale the normalized
   string would not match the ROOT formatter, so DOBs that previously
   parsed would now be rejected.

Both calls now pass Locale.ROOT explicitly, matching the existing
DELCUS / DELACC / CREACC / UPDCUST repository conventions.
@a2chang
Copy link
Copy Markdown
Contributor Author

a2chang commented May 1, 2026

Round-1 review addressed:

  1. (high) CrecustRepository.toDescription now passes Locale.ROOT to both String.format calls (customer number and name slots of PROCTRAN.DESCRIPTION).
  2. (high) CrecustService.parseDateOfBirth now passes Locale.ROOT to String.format("%08d", cobolDate), so the normalized string can never use non-ASCII digits and fail to parse against the now-ROOT-pinned formatter.

No other unpinned String.format calls remain in src/main; the four grep matches that look unpinned are multi-line calls whose Locale.ROOT argument is on the next line.

Local ./mvnw verify green: 198/198. Pushed as a77f568.

augment review

Copy link
Copy Markdown

@augment-app-staging augment-app-staging Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. No suggestions at this time.

Comment augment review to trigger a new review at any time.

@a2chang a2chang merged commit 65a9dbc into main May 1, 2026
1 check passed
@a2chang a2chang deleted the polish/pin-locale-root branch May 1, 2026 21:10
@a2chang a2chang mentioned this pull request May 1, 2026
22 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CREACC: pin Locale.ROOT on DateTimeFormatter.ofPattern("ddMMyyyy") so PROCTRAN.DESCRIPTION stays ASCII-stable

1 participant