Skip to content

fix(java): escape null/true/false discriminator values in generated identifiers - #17430

Open
ChoMinGi wants to merge 2 commits into
fern-api:mainfrom
ChoMinGi:fix/java-null-true-false-discriminator
Open

fix(java): escape null/true/false discriminator values in generated identifiers#17430
ChoMinGi wants to merge 2 commits into
fern-api:mainfrom
ChoMinGi:fix/java-null-true-false-discriminator

Conversation

@ChoMinGi

@ChoMinGi ChoMinGi commented Aug 15, 2026

Copy link
Copy Markdown

Description

Closes #17429

CasingConfiguration.JAVA_RESERVED_KEYWORDS omitted the Java literals null, true, and false. When a discriminated union's discriminator value is one of those strings, the generated Java identifier is left unescaped and JavaPoet rejects it with IllegalArgumentException: not a valid name: null, aborting generation for the whole SDK.

KeyWordUtils.java, a separate reserved-token list used elsewhere in the same generator, already includes all three — this brings CasingConfiguration's fallback set in line with it, using the same escaping convention already used for ordinary keywords (e.g. staticstatic_(...), see seed/java-sdk/reserved-keywords).

Changes Made

  • Added "null", "true", "false" to CasingConfiguration.JAVA_RESERVED_KEYWORDS
  • Added JavaLiteralKeywordTests to CasingConfigurationTest covering all three values plus a control case (default)

Testing


Open in Devin Review

…dentifiers

CasingConfiguration.JAVA_RESERVED_KEYWORDS omitted the Java literals
null, true, and false, so a discriminated union whose discriminator value
is one of those strings produced an unescaped Java identifier and crashed
JavaPoet with "not a valid name: null". KeyWordUtils already treats these
as reserved; this brings CasingConfiguration's fallback set in line with it.

Fixes fern-api#17429

@nitpickybot nitpickybot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

AI Review Summary

Small, targeted fix adding the three Java literals to the reserved-keyword fallback set, with tests. Logic looks correct and matches the existing escaping convention. Only minor nits below.

  • 🔵 2 suggestion(s)

class JavaLiteralKeywordTests {

@ParameterizedTest
@CsvSource({"null,null_", "true,true_", "false,false_"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

@CsvSource is safe here only because nullValues defaults to empty — but if anyone ever sets nullValues = "null" on this class, the null case silently becomes an NPE-flavored mystery. Quote the inputs to make the intent explicit.

Suggested change
@CsvSource({"null,null_", "true,true_", "false,false_"})
@CsvSource({"'null',null_", "'true',true_", "'false',false_"})

@ChoMinGi ChoMinGi Aug 15, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed.
quoted the literals in @CsvSource ('null',null_ etc.) so it's unambiguous regardless of nullValues config.

"throw",
"throws",
"transient",
"true",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

Two independent reserved-word lists (KeyWordUtils and this one) drifting apart is exactly how this bug happened. Consider having one derive from the other, or at minimum add a test asserting JAVA_RESERVED_KEYWORDS is a superset of KeyWordUtils' set so the next divergence fails in CI instead of in a user's generate run.

@ChoMinGi ChoMinGi Aug 15, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Tried that — turns out _ doesn't work the same way.

KeyWordUtils does treat _ as reserved, but in CasingConfiguration it never gets that far. splitWords()'s regex doesn't match underscores at all, so computeName("_") collapses to an empty string before sanitizeName ever runs — I checked, and camelSafe comes back as "", not "_". So adding _ to JAVA_RESERVED_KEYWORDS would just be a no-op.

That looks like a bug in the word-splitting logic rather than the list drifting, so I'd rather leave it out of this PR. Happy to file it separately if that's useful.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

"else",
"enum",
"extends",
"false",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Java generator fix ships without a changelog/version entry

The Java generator bug fix changes shared casing logic (JAVA_RESERVED_KEYWORDS at generators/java/generator-utils/src/main/java/com/fern/java/utils/CasingConfiguration.java:62) without adding a corresponding release entry, so users get no released version containing the fix and no record of it.
Impact: The fix is not published or documented for users of the Java generator.

Repository rule requiring a versions.yml entry for generator changes

REVIEW.md states: "Generator changes (bug fixes or features) should include a versions.yml entry in the appropriate generator directory" and "The type field in changelog entries should match the PR type: fix for bug fixes". This PR only touches CasingConfiguration.java and its test; no entry was added to generators/java/sdk/versions.yml (or the other Java generator directories that consume generator-utils).

Prompt for agents
REVIEW.md requires generator changes to include a versions.yml changelog entry in the appropriate generator directory with type matching the PR type. This PR fixes a Java generator crash caused by unescaped null/true/false discriminator values in CasingConfiguration, but no entry was added. Add a new version entry with a `fix` changelog summary to generators/java/sdk/versions.yml (and any other Java generator versions.yml files that ship generator-utils, e.g. spring/model, if applicable), following the formatting of existing entries.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@ChoMinGi ChoMinGi Aug 15, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed.
added a changelog entry at generators/java/sdk/changes/unreleased/fix-null-true-false-discriminator.yml per the REVIEW.md convention.

- Add versions.yml changelog entry per REVIEW.md convention for generator changes
- Quote null/true/false in @CsvSource so intent is explicit regardless of
  nullValues configuration (nitpickybot suggestion)
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.

Java SDK generation fails on discriminator values null, true, and false

1 participant