From 9aecb8f91ef13b885fbeccf0a5b5fdd6cc9371be Mon Sep 17 00:00:00 2001 From: mikhailnikitin Date: Sun, 1 Mar 2026 18:26:13 +0700 Subject: [PATCH] [kotlin-spring] add skipDefaultValues option (#23076) --- .../languages/KotlinSpringServerCodegen.java | 8 +++++++ .../kotlin-spring/dataClassOptVar.mustache | 2 +- .../kotlin-spring/dataClassReqVar.mustache | 2 +- .../spring/KotlinSpringServerCodegenTest.java | 21 +++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 269075dc780e..4b66383979dc 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -77,6 +77,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen public static final String GRADLE_BUILD_FILE = "gradleBuildFile"; public static final String SERVICE_INTERFACE = "serviceInterface"; public static final String SERVICE_IMPLEMENTATION = "serviceImplementation"; + public static final String SKIP_DEFAULT_VALUES = "skipDefaultValues"; public static final String SKIP_DEFAULT_INTERFACE = "skipDefaultInterface"; public static final String SKIP_DEFAULT_API_INTERFACE = "skipDefaultApiInterface"; public static final String SKIP_DEFAULT_DELEGATE_INTERFACE = "skipDefaultDelegateInterface"; @@ -141,6 +142,7 @@ public String getDescription() { private String title = "OpenAPI Kotlin Spring"; private boolean useBeanValidation = true; @Setter private boolean skipDefaultInterface = false; + @Setter private boolean skipDefaultValues = false; @Setter private boolean skipDefaultApiInterface = false; @Setter private boolean skipDefaultDelegateInterface = false; @Setter private boolean exceptionHandler = true; @@ -243,6 +245,7 @@ public KotlinSpringServerCodegen() { "interfaces. If this is set to true service interfaces will also be generated", serviceImplementation); addSwitch(USE_BEANVALIDATION, "Use BeanValidation API annotations to validate data types", useBeanValidation); addSwitch(SKIP_DEFAULT_INTERFACE, "Whether to skip generation of default implementations for interfaces (Api interfaces or Delegate interfaces depending on the delegatePattern option)", skipDefaultInterface); + addSwitch(SKIP_DEFAULT_VALUES, "Whether to skip default values for data classes", skipDefaultValues); addSwitch(REACTIVE, "use coroutines for reactive behavior", reactive); addSwitch(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files.", interfaceOnly); addSwitch(USE_FEIGN_CLIENT_URL, "Whether to generate Feign client with url parameter.", useFeignClientUrl); @@ -586,6 +589,11 @@ public void processOpts() { } writePropertyBack(SKIP_DEFAULT_INTERFACE, skipDefaultInterface); + if (additionalProperties.containsKey(SKIP_DEFAULT_VALUES)) { + this.setSkipDefaultValues(convertPropertyToBoolean(SKIP_DEFAULT_VALUES)); + } + writePropertyBack(SKIP_DEFAULT_VALUES, skipDefaultValues); + if (additionalProperties.containsKey(REACTIVE)) { if (SPRING_CLOUD_LIBRARY.equals(library)) { throw new IllegalArgumentException("Currently, reactive option doesn't supported by Spring Cloud"); diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache index ab575d4bf9d3..28bfd7676ca9 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache @@ -3,4 +3,4 @@ @ApiModelProperty({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swagger1AnnotationLibrary}}{{#deprecated}} @Deprecated(message = ""){{/deprecated}}{{#vendorExtensions.x-field-extra-annotation}} {{{.}}}{{/vendorExtensions.x-field-extra-annotation}} - @get:JsonProperty("{{{baseName}}}"){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{^defaultValue}}null{{/defaultValue}}{{#defaultValue}}{{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}} \ No newline at end of file + @get:JsonProperty("{{{baseName}}}"){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}?{{^skipDefaultValues}} = {{^defaultValue}}null{{/defaultValue}}{{#defaultValue}}{{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/skipDefaultValues}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache index 92e2875ac08a..d5e0200da425 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/dataClassReqVar.mustache @@ -2,4 +2,4 @@ @Schema({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}required = true, {{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}} @ApiModelProperty({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}required = true, {{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swagger1AnnotationLibrary}}{{#vendorExtensions.x-field-extra-annotation}} {{{.}}}{{/vendorExtensions.x-field-extra-annotation}} - @get:JsonProperty("{{{baseName}}}", required = true){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}} \ No newline at end of file + @get:JsonProperty("{{{baseName}}}", required = true){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}{{^skipDefaultValues}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/skipDefaultValues}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 6ed5446c1cad..2d30f122a205 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -4663,6 +4663,27 @@ public void testSealedResponseInterfacesVoidResponse() throws IOException { Assert.assertTrue(petContent.contains(") : CreatePetResponse {") || petContent.contains(") : CreatePetResponse"), "Pet should implement CreatePetResponse"); } + + @Test + public void testSkipDefaultValues() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(SKIP_DEFAULT_VALUES, true); + + new DefaultGenerator().opts(new ClientOptInput() + .openAPI(TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore.yaml")) + .config(codegen)) + .generate(); + + // Pet model has optional properties that would normally get "= null" defaults + assertFileNotContains( + Paths.get(output + "/src/main/kotlin/org/openapitools/model/Pet.kt"), + "= null" + ); + } }