diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/utils/CasingConfiguration.java b/generators/java/generator-utils/src/main/java/com/fern/java/utils/CasingConfiguration.java index d664f0aee384..ee3e3ff6c365 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/utils/CasingConfiguration.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/utils/CasingConfiguration.java @@ -59,6 +59,7 @@ public final class CasingConfiguration { "else", "enum", "extends", + "false", "final", "finally", "float", @@ -73,6 +74,7 @@ public final class CasingConfiguration { "long", "native", "new", + "null", "package", "private", "protected", @@ -88,6 +90,7 @@ public final class CasingConfiguration { "throw", "throws", "transient", + "true", "try", "void", "volatile", diff --git a/generators/java/generator-utils/src/test/java/com/fern/java/utils/CasingConfigurationTest.java b/generators/java/generator-utils/src/test/java/com/fern/java/utils/CasingConfigurationTest.java index 4da8755bfb64..7ff5aba627d9 100644 --- a/generators/java/generator-utils/src/test/java/com/fern/java/utils/CasingConfigurationTest.java +++ b/generators/java/generator-utils/src/test/java/com/fern/java/utils/CasingConfigurationTest.java @@ -957,4 +957,24 @@ private static CasingConfiguration buildConfig(boolean smartCasing, String langu root.set("casingsConfig", casingsConfig); return CasingConfiguration.fromIrJson(root); } + + // ===== keyword sanitization: Java literals ===== + + @Nested + class JavaLiteralKeywordTests { + + @ParameterizedTest + @CsvSource({"'null',null_", "'true',true_", "'false',false_"}) + void computeName_escapesJavaLiterals(String input, String expectedSafeName) { + CasingConfiguration config = buildConfig(true, "java", null); + CasingConfiguration.NameParts parts = config.computeName(input); + assertThat(parts.camelSafe).isEqualTo(expectedSafeName); + } + + @Test + void computeName_ordinaryKeywordStillEscaped() { + CasingConfiguration config = buildConfig(true, "java", null); + assertThat(config.computeName("default").camelSafe).isEqualTo("default_"); + } + } } diff --git a/generators/java/sdk/changes/unreleased/fix-null-true-false-discriminator.yml b/generators/java/sdk/changes/unreleased/fix-null-true-false-discriminator.yml new file mode 100644 index 000000000000..54358ea2a22c --- /dev/null +++ b/generators/java/sdk/changes/unreleased/fix-null-true-false-discriminator.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Escape the Java literals `null`, `true`, and `false` when they're used as a + discriminated union's discriminator value. Previously the generated Java + identifier was left unescaped (e.g. a static factory method literally named + `null`), which JavaPoet rejected with `not a valid name: null`, aborting + generation. The identifier is now escaped to `null_`/`true_`/`false_` + (matching the existing convention for other reserved words like `static`), + while the serialized discriminator value is unchanged. + type: fix