Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/generators/kotlin-spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useSealedResponseInterfaces|Generate sealed interfaces for endpoint responses that all possible response types implement. Allows controllers to return any valid response type in a type-safe manner (e.g., sealed interface CreateUserResponse implemented by User, ConflictResponse, ErrorResponse)| |false|
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot ≥ 3 (use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
|useSpringBoot4|Generate code and provide dependencies for use with Spring Boot 4.x. Enabling this option will also enable `useJakartaEe`.| |false|
|useSpringBuiltInValidation|Disable `@Validated` at the class level when using built-in validation.| |false|
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|
|useTags|Whether to use tags for creating interface and controller class names| |false|
|xKotlinImplementsFieldsSkip|A list of fields per schema name that should NOT be created with `override` keyword despite their presence in vendor extension `x-kotlin-implements-fields` for the schema. Example: yaml `xKotlinImplementsFieldsSkip: Pet: [photoUrls]` skips `override` for `photoUrls` in schema `Pet`| |empty map|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen

public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
public static final String USE_SPRING_BOOT4 = "useSpringBoot4";
public static final String USE_SPRING_BUILT_IN_VALIDATION = "useSpringBuiltInValidation";
public static final String INCLUDE_HTTP_REQUEST_CONTEXT = "includeHttpRequestContext";
public static final String USE_FLOW_FOR_ARRAY_RETURN_TYPE = "useFlowForArrayReturnType";
public static final String REQUEST_MAPPING_OPTION = "requestMappingMode";
Expand Down Expand Up @@ -190,6 +191,8 @@ public String getDescription() {
protected boolean useSpringBoot3 = false;
@Getter @Setter
protected boolean useSpringBoot4 = false;
@Getter @Setter
protected boolean useSpringBuiltInValidation = false;
protected RequestMappingMode requestMappingMode = RequestMappingMode.controller;
private DocumentationProvider documentationProvider;
private AnnotationLibrary annotationLibrary;
Expand Down Expand Up @@ -286,6 +289,7 @@ public KotlinSpringServerCodegen() {
" (contexts) added to single project.", beanQualifiers);
addSwitch(USE_SPRING_BOOT3, "Generate code and provide dependencies for use with Spring Boot ≥ 3 (use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.", useSpringBoot3);
addSwitch(USE_SPRING_BOOT4, "Generate code and provide dependencies for use with Spring Boot 4.x. Enabling this option will also enable `useJakartaEe`.", useSpringBoot4);
addSwitch(USE_SPRING_BUILT_IN_VALIDATION, "Disable `@Validated` at the class level when using built-in validation.", useSpringBuiltInValidation);
addSwitch(USE_JACKSON_3, "Use Jackson 3 dependencies (tools.jackson package). Only available with `useSpringBoot4`. Defaults to true when `useSpringBoot4` is enabled.", useJackson3);
addSwitch(USE_FLOW_FOR_ARRAY_RETURN_TYPE, "Whether to use Flow for array/collection return types when reactive is enabled. If false, will use List instead.", useFlowForArrayReturnType);
addSwitch(INCLUDE_HTTP_REQUEST_CONTEXT, "Whether to include HttpServletRequest (blocking) or ServerWebExchange (reactive) as additional parameter in generated methods.", includeHttpRequestContext);
Expand Down Expand Up @@ -526,6 +530,10 @@ public void processOpts() {
if (additionalProperties.containsKey(USE_SPRING_BOOT4)) {
this.setUseSpringBoot4(convertPropertyToBoolean(USE_SPRING_BOOT4));
}
if (additionalProperties.containsKey(USE_SPRING_BUILT_IN_VALIDATION)) {
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
this.setUseSpringBuiltInValidation(convertPropertyToBoolean(USE_SPRING_BUILT_IN_VALIDATION));
writePropertyBack(USE_SPRING_BUILT_IN_VALIDATION, useSpringBuiltInValidation);
}
if (additionalProperties.containsKey(INCLUDE_HTTP_REQUEST_CONTEXT)) {
this.setIncludeHttpRequestContext(convertPropertyToBoolean(INCLUDE_HTTP_REQUEST_CONTEXT));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ import org.springframework.http.ResponseEntity

import org.springframework.web.bind.annotation.*
{{#useBeanValidation}}
{{^useSpringBuiltInValidation}}
import org.springframework.validation.annotation.Validated
{{/useSpringBuiltInValidation}}
{{/useBeanValidation}}
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.beans.factory.annotation.Autowired
Expand All @@ -55,7 +57,9 @@ import kotlin.collections.Map

@RestController{{#beanQualifiers}}("{{package}}.{{classname}}Controller"){{/beanQualifiers}}
{{#useBeanValidation}}
{{^useSpringBuiltInValidation}}
@Validated
{{/useSpringBuiltInValidation}}
{{/useBeanValidation}}
{{#swagger1AnnotationLibrary}}
@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import org.springframework.http.ResponseEntity

import org.springframework.web.bind.annotation.*
{{#useBeanValidation}}
{{^useSpringBuiltInValidation}}
import org.springframework.validation.annotation.Validated
{{/useSpringBuiltInValidation}}
{{/useBeanValidation}}
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.beans.factory.annotation.Autowired
Expand All @@ -62,7 +64,9 @@ import kotlin.collections.Map
@RestController
{{/useFeignClient}}
{{#useBeanValidation}}
{{^useSpringBuiltInValidation}}
@Validated
{{/useSpringBuiltInValidation}}
{{/useBeanValidation}}
{{#swagger1AnnotationLibrary}}
@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,101 @@ public void polymorphicJacksonSerialization() throws IOException {
// derived doesn't contain disciminator
TestUtils.assertFileNotContains(birdKt, "val discriminator");
}

@Test(description = "should not generate @Validated annotation on interface when built-in validation option is set to true")
public void shouldEnableBuiltInValidationOptionWhenSetToTrueInterface() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen() ;
codegen.setOutputDir(output.getAbsolutePath());

codegen.setUseSpringBoot3(true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_BEANVALIDATION, true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_SPRING_BUILT_IN_VALIDATION, true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.INTERFACE_ONLY, true);

new DefaultGenerator().opts(
new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/petstore.yaml"))
.config(codegen)
).generate();

final Path userApiKt = Paths.get(output + "/src/main/kotlin/org/openapitools/api/UserApi.kt");
TestUtils.assertFileNotContains(userApiKt, "import org.springframework.validation.annotation.Validated");
TestUtils.assertFileNotContains(userApiKt, "@org.springframework.validation.annotation.Validated");
TestUtils.assertFileNotContains(userApiKt, "@Validated");
}

@Test(description = "should not generate @Validated annotation on controller when built-in validation option is set to true")
public void shouldEnableBuiltInValidationOptionWhenSetToTrueController() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen() ;
codegen.setOutputDir(output.getAbsolutePath());

codegen.setUseSpringBoot3(true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_BEANVALIDATION, true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_SPRING_BUILT_IN_VALIDATION, true);

new DefaultGenerator().opts(
new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/petstore.yaml"))
.config(codegen)
).generate();

final Path userApiKt = Paths.get(output + "/src/main/kotlin/org/openapitools/api/UserApiController.kt");
TestUtils.assertFileNotContains(userApiKt, "import org.springframework.validation.annotation.Validated");
TestUtils.assertFileNotContains(userApiKt, "@org.springframework.validation.annotation.Validated");
TestUtils.assertFileNotContains(userApiKt, "@Validated");
}

@Test(description = "should generate @Validated annotation when built-in validation option is set to false")
public void shouldDisableBuiltInValidationOptionWhenSetToFalse() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen() ;
codegen.setOutputDir(output.getAbsolutePath());

codegen.setUseSpringBoot3(true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_BEANVALIDATION, true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_SPRING_BUILT_IN_VALIDATION, false);
codegen.additionalProperties().put(KotlinSpringServerCodegen.INTERFACE_ONLY, true);

new DefaultGenerator().opts(
new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/petstore.yaml"))
.config(codegen)
).generate();

final Path userApiKt = Paths.get(output + "/src/main/kotlin/org/openapitools/api/UserApi.kt");
TestUtils.assertFileContains(userApiKt, "import org.springframework.validation.annotation.Validated");
TestUtils.assertFileContains(userApiKt, "@Validated");
}

@Test(description = "should generate @Validated annotation when built-in validation option has default value")
public void shouldDisableBuiltInValidationOptionByDefault() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen() ;
codegen.setOutputDir(output.getAbsolutePath());

codegen.additionalProperties().put(KotlinSpringServerCodegen.INTERFACE_ONLY, true);

codegen.setUseSpringBoot3(true);

new DefaultGenerator().opts(
new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/petstore.yaml"))
.config(codegen)
).generate();

final Path userApiKt = Paths.get(output + "/src/main/kotlin/org/openapitools/api/UserApi.kt");
TestUtils.assertFileContains(userApiKt, "import org.springframework.validation.annotation.Validated");
TestUtils.assertFileContains(userApiKt, "@Validated");
}

}
Loading