diff --git a/docs/generators/kotlin.md b/docs/generators/kotlin.md index a6268f931aa4..813ea5918b7a 100644 --- a/docs/generators/kotlin.md +++ b/docs/generators/kotlin.md @@ -25,6 +25,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |companionObject|Whether to generate companion objects in data classes, enabling companion extensions.| |false| |dateLibrary|Option. Date library to use|
**threetenbp-localdatetime**
Threetenbp - Backport of JSR310 (jvm only, for legacy app only)
**kotlinx-datetime**
kotlinx-datetime (preferred for multiplatform)
**string**
String
**java8-localdatetime**
Java 8 native JSR310 (jvm only, for legacy app only)
**java8**
Java 8 native JSR310 (jvm only, preferred for jdk 1.8+)
**threetenbp**
Threetenbp - Backport of JSR310 (jvm only, preferred for jdk < 1.8)
|java8| |enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', 'original', and 'bestEffortBacktick' (like 'original' but tries to wrap values in backticks before falling back to sanitizing, e.g. `name,asc` stays `name,asc` rather than becoming nameCommaAsc; useful for sort/order enums)| |original| +|enumUnknownDefaultCase|Add an `unknown_default_open_api` enum case as a fallback for unrecognized values. Only `moshi`(serializationLibrary) decodes every unknown value to it: `jackson` skips nullable enums, `kotlinx_serialization` skips non-string enums, and neither `gson`(serializationLibrary) nor `multiplatform`(library) decodes to it at all.|
**false**
No changes to the enums are made, this is the default option.
**true**
Each enum gains an `unknown_default_open_api` case.
|false| |explicitApi|Generates code with explicit access modifiers to comply with Kotlin Explicit API Mode.| |false| |failOnUnknownProperties|Fail Jackson de-serialization on unknown properties| |false| |generateOneOfAnyOfWrappers|Generate oneOf, anyOf schemas as wrappers. Only `jvm-retrofit2`(library) with `gson` or `kotlinx_serialization`(serializationLibrary) support this option.| |false| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java index 3898d9a9dc88..90b3c8ad9bcf 100755 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java @@ -316,6 +316,19 @@ public KotlinClientCodegen() { cliOptions.add(CliOption.newBoolean(USE_RESPONSE_AS_RETURN_TYPE, "When using retrofit2 and coroutines, use `Response`<`T`> as return type instead of `T`.", true)); cliOptions.add(CliOption.newBoolean(USE_JACKSON_3, "Use Jackson 3 dependencies (tools.jackson package). Requires serializationLibrary=jackson. Incompatible with openApiNullable.")); + + // AbstractKotlinCodegen calls cliOptions.clear(), dropping DefaultCodegen's registration. + // Re-registered on kotlin alone: no other Kotlin generator's templates implement the fallback. + CliOption enumUnknownDefaultCaseOpt = CliOption.newBoolean( + CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, + "Add an `unknown_default_open_api` enum case as a fallback for unrecognized values. Only `moshi`(serializationLibrary) decodes every unknown value to it: `jackson` skips nullable enums, `kotlinx_serialization` skips non-string enums, and neither `gson`(serializationLibrary) nor `multiplatform`(library) decodes to it at all."); + Map enumUnknownDefaultCaseOpts = new HashMap<>(); + enumUnknownDefaultCaseOpts.put("false", + "No changes to the enums are made, this is the default option."); + enumUnknownDefaultCaseOpts.put("true", + "Each enum gains an `unknown_default_open_api` case."); + enumUnknownDefaultCaseOpt.setEnum(enumUnknownDefaultCaseOpts); + cliOptions.add(enumUnknownDefaultCaseOpt); } @Override diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java index 921cd035aeb4..dad52b7ae72b 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java @@ -42,6 +42,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import static org.openapitools.codegen.CodegenConstants.*; import static org.openapitools.codegen.languages.KotlinClientCodegen.*; @@ -1505,4 +1506,21 @@ public void testNoDefaultImplWhenNeitherSourceIsSet() throws IOException { Assert.assertTrue(sawJsonTypeInfo, "Expected at least one generated model with @JsonTypeInfo to exercise the code path"); } + + /** + * AbstractKotlinCodegen calls cliOptions.clear(), so an option inherited from DefaultCodegen stays + * functional while vanishing from config-help and docs/generators/kotlin.md. That is how + * enumUnknownDefaultCase went undocumented for years; this guards the re-registration. + */ + @Test + public void testEnumUnknownDefaultCaseIsRegisteredAsCliOption() { + CliOption option = new KotlinClientCodegen().cliOptions().stream() + .filter(o -> CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE.equals(o.getOpt())) + .findFirst() + .orElse(null); + + Assert.assertNotNull(option, CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE + " is not registered"); + Assert.assertEquals(option.getDefault(), "false"); + Assert.assertEquals(option.getEnum().keySet(), Set.of("true", "false")); + } }