From f0e587e95cc1e29d30929ce0d5d9fb37c83f59fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Thu, 12 Feb 2026 22:49:27 +0100 Subject: [PATCH 01/24] add x-kotlin-implements --- .../languages/KotlinSpringServerCodegen.java | 74 +++++++- .../main/resources/kotlin-spring/api.mustache | 4 +- .../kotlin-spring/apiDelegate.mustache | 4 +- .../kotlin-spring/apiInterface.mustache | 6 +- .../resources/kotlin-spring/api_test.mustache | 3 +- .../spring/KotlinSpringServerCodegenTest.java | 158 ++++++++++++++++++ 6 files changed, 237 insertions(+), 12 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 98e1f003b019..bc162046c86c 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 @@ -447,6 +447,12 @@ public void processOpts() { additionalProperties.put(DOCUMENTATION_PROVIDER, DocumentationProvider.NONE); additionalProperties.put(ANNOTATION_LIBRARY, AnnotationLibrary.NONE); } + if (additionalProperties.containsKey(USE_SPRING_BOOT3)) { + this.setUseSpringBoot3(convertPropertyToBoolean(USE_SPRING_BOOT3)); + } + if (additionalProperties.containsKey(INCLUDE_HTTP_REQUEST_CONTEXT)) { + this.setIncludeHttpRequestContext(convertPropertyToBoolean(INCLUDE_HTTP_REQUEST_CONTEXT)); + } if (isModelMutable()) { typeMapping.put("array", "kotlin.collections.MutableList"); @@ -470,6 +476,13 @@ public void processOpts() { // used later in recursive import in postProcessingModels importMapping.put("com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonCreator"); + // Spring-specific import mappings for x-spring-paginated support + importMapping.put("ApiIgnore", "springfox.documentation.annotations.ApiIgnore"); + importMapping.put("ParameterObject", "org.springdoc.api.annotations.ParameterObject"); + if (useSpringBoot3) { + importMapping.put("ParameterObject", "org.springdoc.core.annotations.ParameterObject"); + } + if (!additionalProperties.containsKey(CodegenConstants.LIBRARY)) { additionalProperties.put(CodegenConstants.LIBRARY, library); } @@ -642,13 +655,6 @@ public void processOpts() { if (additionalProperties.containsKey(USE_TAGS)) { this.setUseTags(Boolean.parseBoolean(additionalProperties.get(USE_TAGS).toString())); } - - if (additionalProperties.containsKey(USE_SPRING_BOOT3)) { - this.setUseSpringBoot3(convertPropertyToBoolean(USE_SPRING_BOOT3)); - } - if (additionalProperties.containsKey(INCLUDE_HTTP_REQUEST_CONTEXT)) { - this.setIncludeHttpRequestContext(convertPropertyToBoolean(INCLUDE_HTTP_REQUEST_CONTEXT)); - } if (isUseSpringBoot3()) { if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) { throw new IllegalArgumentException(DocumentationProvider.SPRINGFOX.getPropertyName() + " is not supported with Spring Boot > 3.x"); @@ -872,6 +878,60 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera } } + /** + * Processes operations to support the x-spring-paginated vendor extension. + * + * When x-spring-paginated is set to true on an operation, this method: + * - Adds org.springframework.data.domain.Pageable parameter to the method signature + * - Removes the default Spring Data Web pagination query parameters (page, size, sort) + * - Adds appropriate imports (Pageable, ApiIgnore for springfox, ParameterObject for springdoc) + * + * Parameter ordering in generated methods: + * 1. Regular OpenAPI parameters (allParams) + * 2. Optional HttpServletRequest/ServerWebExchange (if includeHttpRequestContext is enabled) + * 3. Pageable parameter (if x-spring-paginated is true) + * + * This implementation mirrors the behavior in SpringCodegen for consistency. + * + * @param path the operation path + * @param httpMethod the HTTP method + * @param operation the OpenAPI operation + * @param servers the list of servers + * @return the processed CodegenOperation + */ + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) { + // add Pageable import only if x-spring-paginated explicitly used + // this allows to use a custom Pageable schema without importing Spring Pageable. + if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-spring-paginated"))) { + importMapping.putIfAbsent("Pageable", "org.springframework.data.domain.Pageable"); + } + + CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers); + + // add org.springframework.data.domain.Pageable import when needed + if (codegenOperation.vendorExtensions.containsKey("x-spring-paginated")) { + codegenOperation.imports.add("Pageable"); + if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) { + codegenOperation.imports.add("ApiIgnore"); + } + if (DocumentationProvider.SPRINGDOC.equals(getDocumentationProvider())) { + codegenOperation.imports.add("ParameterObject"); + } + + // #8315 Spring Data Web default query params recognized by Pageable + List defaultPageableQueryParams = new ArrayList<>( + Arrays.asList("page", "size", "sort") + ); + + // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used + codegenOperation.queryParams.removeIf(param -> defaultPageableQueryParams.contains(param.baseName)); + codegenOperation.allParams.removeIf(param -> param.isQueryParam && defaultPageableQueryParams.contains(param.baseName)); + } + + return codegenOperation; + } + @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index 07d45a3e505c..3b9e4fe25805 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -95,7 +95,9 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v ) {{#reactive}}{{^isArray}}suspend {{/isArray}}{{#isArray}}{{^useFlowForArrayReturnType}}suspend {{/useFlowForArrayReturnType}}{{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}} {{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, - {{/hasParams}}{{#swagger1AnnotationLibrary}}@ApiParam(hidden = true) {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true) {{/swagger2AnnotationLibrary}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#hasParams}} + {{/hasParams}}{{#swagger1AnnotationLibrary}}@ApiParam(hidden = true) {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true) {{/swagger2AnnotationLibrary}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, + {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, + {{/includeHttpRequestContext}}{{/hasParams}}{{#swagger1AnnotationLibrary}}@ApiParam(hidden = true) {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true) {{/swagger2AnnotationLibrary}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}{{#hasParams}} {{/hasParams}}): {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}} { return {{>returnValue}} } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache index 5ae576a08bec..c317d43bf56e 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache @@ -34,7 +34,9 @@ interface {{classname}}Delegate { */ {{#reactive}}{{^isArray}}suspend {{/isArray}}{{#isArray}}{{^useFlowForArrayReturnType}}suspend {{/useFlowForArrayReturnType}}{{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{{paramName}}}: {{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}{{>optionalDataType}}{{/isArray}}{{#isArray}}{{#isBodyParam}}Flow<{{{baseType}}}>{{/isBodyParam}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{/isArray}}{{/reactive}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, - {{/hasParams}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}): {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{^skipDefaultDelegateInterface}} { + {{/hasParams}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, + {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, + {{/includeHttpRequestContext}}{{/hasParams}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}): {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{^skipDefaultDelegateInterface}} { {{>methodBody}}{{! prevent indent}} }{{/skipDefaultDelegateInterface}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache index 67a9c8f4d096..0df5348fbeef 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache @@ -110,13 +110,15 @@ interface {{classname}} { ) {{#reactive}}{{^isArray}}suspend {{/isArray}}{{#isArray}}{{^useFlowForArrayReturnType}}suspend {{/useFlowForArrayReturnType}}{{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}} {{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, - {{/hasParams}}{{#swagger1AnnotationLibrary}}@ApiParam(hidden = true) {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true) {{/swagger2AnnotationLibrary}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#hasParams}} + {{/hasParams}}{{#swagger1AnnotationLibrary}}@ApiParam(hidden = true) {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true) {{/swagger2AnnotationLibrary}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, + {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, + {{/includeHttpRequestContext}}{{/hasParams}}{{#swagger1AnnotationLibrary}}@ApiParam(hidden = true) {{/swagger1AnnotationLibrary}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true) {{/swagger2AnnotationLibrary}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}{{#hasParams}} {{/hasParams}}): {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{^skipDefaultApiInterface}} { {{^isDelegate}} return {{>returnValue}} {{/isDelegate}} {{#isDelegate}} - return getDelegate().{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}request{{/reactive}}{{/includeHttpRequestContext}}) + return getDelegate().{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}request{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}) {{/isDelegate}} }{{/skipDefaultApiInterface}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api_test.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api_test.mustache index eda2afcd0c18..8950633ae979 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api_test.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api_test.mustache @@ -35,7 +35,8 @@ class {{classname}}Test { val {{{paramName}}}: {{>optionalDataType}} = TODO() {{/allParams}} {{#includeHttpRequestContext}}val {{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}} = TODO(){{/includeHttpRequestContext}} - val response: {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}} = api.{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}request{{/reactive}}{{/includeHttpRequestContext}}) + {{#vendorExtensions.x-spring-paginated}}val pageable: Pageable = TODO(){{/vendorExtensions.x-spring-paginated}} + val response: {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}} = api.{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}request{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}) // TODO: test validations } 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 12d52f58de59..22e98216117c 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 @@ -3666,6 +3666,164 @@ public void testXMinimumMessageAndXMaximumMessage_long() throws IOException { .hasNotAttributes(List.of("message")); } + @Test + public void springPaginatedWithSpringDoc() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "import org.springdoc.api.annotations.ParameterObject"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + assertFileContains(petApi.toPath(), "@Parameter(hidden = true) pageable: Pageable"); + } + + @Test + public void springPaginatedWithSpringDocAndSpringBoot3() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(USE_SPRING_BOOT3, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "import org.springdoc.core.annotations.ParameterObject"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + } + + @Test + public void springPaginatedWithSpringFox() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springfox"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "import springfox.documentation.annotations.ApiIgnore"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + assertFileContains(petApi.toPath(), "@ApiParam(hidden = true) pageable: Pageable"); + } + + @Test + public void springPaginatedQueryParamsRemoved() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test that page, size, and sort query params are removed but other params remain + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "tags: kotlin.collections.List"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + assertFileNotContains(petApi.toPath(), "page:"); + assertFileNotContains(petApi.toPath(), "sort:"); + // Header param size should remain, query param size should be removed + assertFileContains(petApi.toPath(), "@RequestHeader(value = \"size\""); + } + + @Test + public void springPaginatedWithReactive() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(REACTIVE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test that pageable works in reactive mode + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + } + + @Test + public void springPaginatedWithIncludeHttpRequestContext() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(INCLUDE_HTTP_REQUEST_CONTEXT, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test that pageable comes after request parameter + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "request: javax.servlet.http.HttpServletRequest"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + } + + @Test + public void springPaginatedWithReactiveAndIncludeHttpRequestContext() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(REACTIVE, "true"); + additionalProperties.put(INCLUDE_HTTP_REQUEST_CONTEXT, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test that pageable comes after exchange parameter in reactive mode + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "exchange: org.springframework.web.server.ServerWebExchange"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + } + + @Test + public void springPaginatedWithDelegate() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(DELEGATE_PATTERN, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test that pageable is in delegate interface + File petApiDelegate = files.get("PetApiDelegate.kt"); + assertFileContains(petApiDelegate.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApiDelegate.toPath(), "pageable: Pageable"); + } + + @Test + public void customPageableSchemaNotOverridden_issue13052() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/bugs/issue_13052.yaml", additionalProperties); + + // Custom Pageable model should be used instead of Spring's Pageable + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.openapitools.model.Pageable"); + assertFileNotContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileNotContains(petApi.toPath(), "import org.springdoc.core.annotations.ParameterObject"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + } + private Map generateFromContract(String url) throws IOException { return generateFromContract(url, new HashMap<>(), new HashMap<>()); } From 9713d9ff0d959ecfa736f78c310794ae7ab09c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Thu, 12 Feb 2026 23:17:44 +0100 Subject: [PATCH 02/24] implement tests --- .../spring/KotlinSpringServerCodegenTest.java | 151 +++++++++++++++++- .../spring/petstore-with-spring-pageable.yaml | 52 ++++++ 2 files changed, 202 insertions(+), 1 deletion(-) 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 22e98216117c..4a2102855a33 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 @@ -3813,7 +3813,7 @@ public void customPageableSchemaNotOverridden_issue13052() throws Exception { additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); additionalProperties.put(INTERFACE_ONLY, "true"); additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); - + Map files = generateFromContract("src/test/resources/bugs/issue_13052.yaml", additionalProperties); // Custom Pageable model should be used instead of Spring's Pageable @@ -3824,6 +3824,155 @@ public void customPageableSchemaNotOverridden_issue13052() throws Exception { assertFileContains(petApi.toPath(), "pageable: Pageable"); } + @Test + public void springPaginatedWithNoDocumentationProvider() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "none"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Pageable should be added but no annotation imports + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + assertFileNotContains(petApi.toPath(), "import springfox.documentation.annotations.ApiIgnore"); + assertFileNotContains(petApi.toPath(), "import org.springdoc.api.annotations.ParameterObject"); + assertFileNotContains(petApi.toPath(), "@ApiIgnore pageable"); + assertFileNotContains(petApi.toPath(), "@ParameterObject pageable"); + } + + @Test + public void springPaginatedWithSwagger1AnnotationLibrary() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springfox"); + additionalProperties.put(ANNOTATION_LIBRARY, "swagger1"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test with swagger1 annotations + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petApi.toPath(), "import springfox.documentation.annotations.ApiIgnore"); + assertFileContains(petApi.toPath(), "@ApiParam(hidden = true) pageable: Pageable"); + } + + @Test + public void springPaginatedNoParamsNoContext() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test operation listAllPets which has no parameters except pageable + File petApi = files.get("PetApi.kt"); + assertFileContains(petApi.toPath(), "fun listAllPets(@Parameter(hidden = true) pageable: Pageable)"); + } + + @Test + public void springPaginatedMixedOperations() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + + // Operation with x-spring-paginated should have Pageable + assertFileContains(petApi.toPath(), "fun findPetsByStatus("); + assertFileContains(petApi.toPath(), "pageable: Pageable"); + + // Operation without x-spring-paginated should NOT have Pageable + assertFileContains(petApi.toPath(), "fun addPet("); + // Verify addPet doesn't have pageable (it has body param only) + String content = new String(java.nio.file.Files.readAllBytes(petApi.toPath())); + String addPetMethod = content.substring( + content.indexOf("fun addPet("), + content.indexOf(")", content.indexOf("fun addPet(")) + 1 + ); + Assert.assertFalse(addPetMethod.contains("pageable"), + "addPet should not have pageable parameter"); + } + + @Test + public void springPaginatedWithServiceInterface() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(SERVICE_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Test that pageable is in service interface + File petService = files.get("PetService.kt"); + if (petService != null) { + assertFileContains(petService.toPath(), "import org.springframework.data.domain.Pageable"); + assertFileContains(petService.toPath(), "pageable: Pageable"); + } + } + + @Test + public void springPaginatedParameterOrdering() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(INCLUDE_HTTP_REQUEST_CONTEXT, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Verify exact parameter ordering: allParams -> request -> pageable + File petApi = files.get("PetApi.kt"); + String content = new String(java.nio.file.Files.readAllBytes(petApi.toPath())); + + // Find findPetsByStatus method + int methodStart = content.indexOf("fun findPetsByStatus("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + // Verify order: status param comes before request, request comes before pageable + int statusPos = methodSignature.indexOf("status:"); + int requestPos = methodSignature.indexOf("request:"); + int pageablePos = methodSignature.indexOf("pageable:"); + + Assert.assertTrue(statusPos > 0, "status parameter should exist"); + Assert.assertTrue(requestPos > statusPos, "request should come after status"); + Assert.assertTrue(pageablePos > requestPos, "pageable should come after request"); + } + + @Test + public void springPaginatedDelegateCallPassesPageable() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(DELEGATE_PATTERN, "true"); + additionalProperties.put(INTERFACE_ONLY, "false"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + // Verify that interface method calls delegate with pageable parameter + File petApi = files.get("PetApi.kt"); + String content = new String(java.nio.file.Files.readAllBytes(petApi.toPath())); + + // Check for delegate call pattern with pageable + if (content.contains("getDelegate().findPetsByStatus")) { + assertFileContains(petApi.toPath(), "getDelegate().findPetsByStatus("); + assertFileContains(petApi.toPath(), "pageable)"); + } + } + private Map generateFromContract(String url) throws IOException { return generateFromContract(url, new HashMap<>(), new HashMap<>()); } diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml index dcf0075a21f0..792521466546 100644 --- a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml @@ -191,6 +191,58 @@ paths: - write:pets - read:pets x-spring-paginated: true + /pet/all: + get: + tags: + - pet + summary: List all pets + description: Returns all pets with pagination support + operationId: listAllPets + parameters: + - name: page + in: query + description: "The page number to return. Test QueryParam for issue #8315 - must be removed when x-spring-paginated:true is used." + required: false + schema: + type: integer + format: int32 + default: 0 + - name: size + in: query + description: "The number of items to return per page. Test QueryParam for issue #8315 - must be removed when x-spring-paginated:true is used." + required: false + schema: + type: integer + format: int32 + default: 20 + - name: sort + in: query + description: "The sort order. Test QueryParam for issue #8315 - must be removed when x-spring-paginated:true is used." + required: false + schema: + type: string + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + 400: + description: Invalid status value + content: {} + security: + - petstore_auth: + - write:pets + - read:pets + x-spring-paginated: true /pet/{petId}: get: tags: From 7bc73e15611b4ec278578cb2400aa164a908768b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Thu, 12 Feb 2026 23:21:03 +0100 Subject: [PATCH 03/24] update samples --- .../java/org/openapitools/api/PetApi.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java b/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java index b549aef534ba..acadc4d62506 100644 --- a/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java @@ -210,6 +210,40 @@ ResponseEntity getPetById( ); + String PATH_LIST_ALL_PETS = "/pet/all"; + /** + * GET /pet/all : List all pets + * Returns all pets with pagination support + * + * @return successful operation (status code 200) + * or Invalid status value (status code 400) + */ + @Operation( + operationId = "listAllPets", + summary = "List all pets", + description = "Returns all pets with pagination support", + tags = { "pet" }, + responses = { + @ApiResponse(responseCode = "200", description = "successful operation", content = { + @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = Pet.class))), + @Content(mediaType = "application/xml", array = @ArraySchema(schema = @Schema(implementation = Pet.class))) + }), + @ApiResponse(responseCode = "400", description = "Invalid status value") + }, + security = { + @SecurityRequirement(name = "petstore_auth", scopes={ "write:pets", "read:pets" }) + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = PetApi.PATH_LIST_ALL_PETS, + produces = { "application/json", "application/xml" } + ) + ResponseEntity> listAllPets( + @ParameterObject final Pageable pageable + ); + + String PATH_UPDATE_PET = "/pet"; /** * PUT /pet : Update an existing pet From 3814cacad786091e3dd9c0a5e9ee5b748b270e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Thu, 12 Feb 2026 23:38:32 +0100 Subject: [PATCH 04/24] fix tests - forbidden api issue --- .../kotlin/spring/KotlinSpringServerCodegenTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 4a2102855a33..1ab6a7ecb99b 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 @@ -3896,7 +3896,7 @@ public void springPaginatedMixedOperations() throws Exception { // Operation without x-spring-paginated should NOT have Pageable assertFileContains(petApi.toPath(), "fun addPet("); // Verify addPet doesn't have pageable (it has body param only) - String content = new String(java.nio.file.Files.readAllBytes(petApi.toPath())); + String content = Files.readString(petApi.toPath()); String addPetMethod = content.substring( content.indexOf("fun addPet("), content.indexOf(")", content.indexOf("fun addPet(")) + 1 @@ -3935,8 +3935,8 @@ public void springPaginatedParameterOrdering() throws Exception { // Verify exact parameter ordering: allParams -> request -> pageable File petApi = files.get("PetApi.kt"); - String content = new String(java.nio.file.Files.readAllBytes(petApi.toPath())); - + String content = Files.readString(petApi.toPath()); + // Find findPetsByStatus method int methodStart = content.indexOf("fun findPetsByStatus("); int methodEnd = content.indexOf("): ResponseEntity", methodStart); @@ -3964,8 +3964,8 @@ public void springPaginatedDelegateCallPassesPageable() throws Exception { // Verify that interface method calls delegate with pageable parameter File petApi = files.get("PetApi.kt"); - String content = new String(java.nio.file.Files.readAllBytes(petApi.toPath())); - + String content = Files.readString(petApi.toPath()); + // Check for delegate call pattern with pageable if (content.contains("getDelegate().findPetsByStatus")) { assertFileContains(petApi.toPath(), "getDelegate().findPetsByStatus("); From deda2225d13d4ff82d7673e7109a1b328b8cb3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Thu, 12 Feb 2026 23:54:33 +0100 Subject: [PATCH 05/24] add samples --- .../petstore-with-x-kotlin-implements.yaml | 408 ++++++++++++++++++ .../kotlin/org/openapitools/api/PetApi.kt | 245 +++++++++++ .../org/openapitools/api/PetApiDelegate.kt | 85 ++++ .../kotlin/org/openapitools/api/PetApi.kt | 227 ++++++++++ 4 files changed, 965 insertions(+) diff --git a/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml b/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml index 276e8595e33c..8e6b8b24e9e7 100644 --- a/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml @@ -486,6 +486,414 @@ paths: description: Invalid username supplied '404': description: User not found + # Comprehensive x-spring-paginated test endpoints + /pet/paginated/all: + get: + tags: + - pet + summary: List all pets with pagination (only pagination params) + description: Tests x-spring-paginated with ONLY page/size/sort params that will be removed + operationId: listAllPetsPaginated + parameters: + - name: page + in: query + description: Page number - will be removed when x-spring-paginated is true + schema: + type: integer + format: int32 + default: 0 + - name: size + in: query + description: Page size - will be removed when x-spring-paginated is true + schema: + type: integer + format: int32 + default: 20 + - name: sort + in: query + description: Sort order - will be removed when x-spring-paginated is true + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/withParams: + get: + tags: + - pet + summary: List pets with filtering and pagination + description: Tests x-spring-paginated with regular params + pagination params + operationId: listPetsWithFilterPaginated + parameters: + - name: status + in: query + description: Filter by status - will be kept + schema: + type: string + enum: + - available + - pending + - sold + - name: name + in: query + description: Filter by name - will be kept + schema: + type: string + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + format: int32 + - name: size + in: query + description: Page size - will be removed + schema: + type: integer + format: int32 + - name: sort + in: query + description: Sort order - will be removed + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/headerSize: + get: + tags: + - pet + summary: List pets with header param named 'size' + description: Tests that header param 'size' is preserved while query param 'size' is removed + operationId: listPetsWithHeaderSize + parameters: + - name: size + in: header + description: Size header - must NOT be removed (different from query param) + schema: + type: string + - name: category + in: query + description: Filter by category - will be kept + schema: + type: string + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + - name: size + in: query + description: Page size query param - will be removed + schema: + type: integer + - name: sort + in: query + description: Sort order - will be removed + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/noPagination: + get: + tags: + - pet + summary: List pets WITHOUT x-spring-paginated + description: Tests that operations without x-spring-paginated keep all params + operationId: listPetsNoPagination + parameters: + - name: status + in: query + description: Filter by status + schema: + type: string + - name: page + in: query + description: Page number - will be KEPT (no x-spring-paginated) + schema: + type: integer + - name: size + in: query + description: Page size - will be KEPT (no x-spring-paginated) + schema: + type: integer + - name: sort + in: query + description: Sort order - will be KEPT (no x-spring-paginated) + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + # NO x-spring-paginated - all params should remain + /pet/paginated/{ownerId}: + get: + tags: + - pet + summary: List pets by owner with pagination + description: Tests x-spring-paginated with path param + query params + operationId: listPetsByOwnerPaginated + parameters: + - name: ownerId + in: path + description: Owner ID - will be kept + required: true + schema: + type: integer + format: int64 + - name: includeAdopted + in: query + description: Include adopted pets - will be kept + schema: + type: boolean + default: false + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + - name: size + in: query + description: Page size - will be removed + schema: + type: integer + - name: sort + in: query + description: Sort order - will be removed + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/multiParam: + get: + tags: + - pet + summary: List pets with many query params + description: Tests x-spring-paginated removes only page/size/sort + operationId: listPetsMultipleParams + parameters: + - name: name + in: query + description: Filter by name - will be kept + schema: + type: string + - name: minAge + in: query + description: Minimum age - will be kept + schema: + type: integer + - name: maxAge + in: query + description: Maximum age - will be kept + schema: + type: integer + - name: tags + in: query + description: Filter by tags - will be kept + schema: + type: array + items: + type: string + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + - name: size + in: query + description: Page size - will be removed + schema: + type: integer + - name: sort + in: query + description: Sort order - will be removed + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/partialParams: + get: + tags: + - pet + summary: List pets with only some pagination params + description: Tests x-spring-paginated with only page and size (no sort) + operationId: listPetsPartialPagination + parameters: + - name: status + in: query + description: Filter by status - will be kept + schema: + type: string + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + - name: size + in: query + description: Page size - will be removed + schema: + type: integer + # Intentionally NO 'sort' parameter + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/pathOnly: + get: + tags: + - pet + summary: List pets with path and header params only + description: Tests x-spring-paginated with no query params except pagination + operationId: listPetsByIdPaginated + parameters: + - name: petId + in: path + description: Pet ID + required: true + schema: + type: integer + format: int64 + - name: X-Request-ID + in: header + description: Request ID for tracing + schema: + type: string + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + - name: size + in: query + description: Page size - will be removed + schema: + type: integer + - name: sort + in: query + description: Sort order - will be removed + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true + /pet/paginated/mixed: + get: + tags: + - pet + summary: Mixed params - path, header, query, and pagination + description: Comprehensive test with all parameter types + operationId: listPetsMixedParams + parameters: + - name: categoryId + in: path + description: Category ID + required: true + schema: + type: integer + format: int64 + - name: Authorization + in: header + description: Authorization header + schema: + type: string + - name: X-Tenant-ID + in: header + description: Tenant ID + schema: + type: string + - name: status + in: query + description: Status filter + schema: + type: string + - name: includeInactive + in: query + description: Include inactive pets + schema: + type: boolean + - name: page + in: query + description: Page number - will be removed + schema: + type: integer + - name: size + in: query + description: Page size - will be removed + schema: + type: integer + - name: sort + in: query + description: Sort order - will be removed + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + x-spring-paginated: true components: securitySchemes: diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt index fe980df7e0b8..2d904f839901 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -6,6 +6,7 @@ package org.openapitools.api import org.openapitools.model.ModelApiResponse +import org.springframework.data.domain.Pageable import org.openapitools.model.Pet import io.swagger.annotations.Api import io.swagger.annotations.ApiOperation @@ -165,6 +166,241 @@ interface PetApi { } + @ApiOperation( + value = "List all pets with pagination (only pagination params)", + nickname = "listAllPetsPaginated", + notes = "Tests x-spring-paginated with ONLY page/size/sort params that will be removed", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/all" + value = [PATH_LIST_ALL_PETS_PAGINATED], + produces = ["application/json"] + ) + fun listAllPetsPaginated(@ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable): ResponseEntity> { + return getDelegate().listAllPetsPaginated(exchange, pageable) + } + + + @ApiOperation( + value = "List pets with path and header params only", + nickname = "listPetsByIdPaginated", + notes = "Tests x-spring-paginated with no query params except pagination", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/pathOnly" + value = [PATH_LIST_PETS_BY_ID_PAGINATED], + produces = ["application/json"] + ) + fun listPetsByIdPaginated( + @ApiParam(value = "Pet ID", required = true) @PathVariable("petId") petId: kotlin.Long, + @ApiParam(value = "Request ID for tracing") @RequestHeader(value = "X-Request-ID", required = false) xRequestID: kotlin.String?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsByIdPaginated(petId, xRequestID, exchange, pageable) + } + + + @ApiOperation( + value = "List pets by owner with pagination", + nickname = "listPetsByOwnerPaginated", + notes = "Tests x-spring-paginated with path param + query params", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/{ownerId}" + value = [PATH_LIST_PETS_BY_OWNER_PAGINATED], + produces = ["application/json"] + ) + fun listPetsByOwnerPaginated( + @ApiParam(value = "Owner ID - will be kept", required = true) @PathVariable("ownerId") ownerId: kotlin.Long, + @ApiParam(value = "Include adopted pets - will be kept", defaultValue = "false") @Valid @RequestParam(value = "includeAdopted", required = false, defaultValue = "false") includeAdopted: kotlin.Boolean, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsByOwnerPaginated(ownerId, includeAdopted, exchange, pageable) + } + + + @ApiOperation( + value = "Mixed params - path, header, query, and pagination", + nickname = "listPetsMixedParams", + notes = "Comprehensive test with all parameter types", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/mixed" + value = [PATH_LIST_PETS_MIXED_PARAMS], + produces = ["application/json"] + ) + fun listPetsMixedParams( + @ApiParam(value = "Category ID", required = true) @PathVariable("categoryId") categoryId: kotlin.Long, + @ApiParam(value = "Authorization header") @RequestHeader(value = "Authorization", required = false) authorization: kotlin.String?, + @ApiParam(value = "Tenant ID") @RequestHeader(value = "X-Tenant-ID", required = false) xTenantID: kotlin.String?, + @ApiParam(value = "Status filter") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(value = "Include inactive pets") @Valid @RequestParam(value = "includeInactive", required = false) includeInactive: kotlin.Boolean?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsMixedParams(categoryId, authorization, xTenantID, status, includeInactive, exchange, pageable) + } + + + @ApiOperation( + value = "List pets with many query params", + nickname = "listPetsMultipleParams", + notes = "Tests x-spring-paginated removes only page/size/sort", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/multiParam" + value = [PATH_LIST_PETS_MULTIPLE_PARAMS], + produces = ["application/json"] + ) + fun listPetsMultipleParams( + @ApiParam(value = "Filter by name - will be kept") @Valid @RequestParam(value = "name", required = false) name: kotlin.String?, + @ApiParam(value = "Minimum age - will be kept") @Valid @RequestParam(value = "minAge", required = false) minAge: kotlin.Int?, + @ApiParam(value = "Maximum age - will be kept") @Valid @RequestParam(value = "maxAge", required = false) maxAge: kotlin.Int?, + @ApiParam(value = "Filter by tags - will be kept") @Valid @RequestParam(value = "tags", required = false) tags: kotlin.collections.List?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsMultipleParams(name, minAge, maxAge, tags, exchange, pageable) + } + + + @ApiOperation( + value = "List pets WITHOUT x-spring-paginated", + nickname = "listPetsNoPagination", + notes = "Tests that operations without x-spring-paginated keep all params", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/noPagination" + value = [PATH_LIST_PETS_NO_PAGINATION], + produces = ["application/json"] + ) + fun listPetsNoPagination( + @ApiParam(value = "Filter by status") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(value = "Page number - will be KEPT (no x-spring-paginated)") @Valid @RequestParam(value = "page", required = false) page: kotlin.Int?, + @ApiParam(value = "Page size - will be KEPT (no x-spring-paginated)") @Valid @RequestParam(value = "size", required = false) size: kotlin.Int?, + @ApiParam(value = "Sort order - will be KEPT (no x-spring-paginated)") @Valid @RequestParam(value = "sort", required = false) sort: kotlin.String?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange + ): ResponseEntity> { + return getDelegate().listPetsNoPagination(status, page, size, sort, exchange) + } + + + @ApiOperation( + value = "List pets with only some pagination params", + nickname = "listPetsPartialPagination", + notes = "Tests x-spring-paginated with only page and size (no sort)", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/partialParams" + value = [PATH_LIST_PETS_PARTIAL_PAGINATION], + produces = ["application/json"] + ) + fun listPetsPartialPagination( + @ApiParam(value = "Filter by status - will be kept") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsPartialPagination(status, exchange, pageable) + } + + + @ApiOperation( + value = "List pets with filtering and pagination", + nickname = "listPetsWithFilterPaginated", + notes = "Tests x-spring-paginated with regular params + pagination params", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/withParams" + value = [PATH_LIST_PETS_WITH_FILTER_PAGINATED], + produces = ["application/json"] + ) + fun listPetsWithFilterPaginated( + @ApiParam(value = "Filter by status - will be kept", allowableValues = "available, pending, sold") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(value = "Filter by name - will be kept") @Valid @RequestParam(value = "name", required = false) name: kotlin.String?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsWithFilterPaginated(status, name, exchange, pageable) + } + + + @ApiOperation( + value = "List pets with header param named 'size'", + nickname = "listPetsWithHeaderSize", + notes = "Tests that header param 'size' is preserved while query param 'size' is removed", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/headerSize" + value = [PATH_LIST_PETS_WITH_HEADER_SIZE], + produces = ["application/json"] + ) + fun listPetsWithHeaderSize( + @ApiParam(value = "Size header - must NOT be removed (different from query param)") @RequestHeader(value = "size", required = false) size: kotlin.String?, + @ApiParam(value = "Filter by category - will be kept") @Valid @RequestParam(value = "category", required = false) category: kotlin.String?, + @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> { + return getDelegate().listPetsWithHeaderSize(size, category, exchange, pageable) + } + + @ApiOperation( value = "Update an existing pet", nickname = "updatePet", @@ -246,6 +482,15 @@ interface PetApi { const val PATH_FIND_PETS_BY_STATUS: String = "/pet/findByStatus" const val PATH_FIND_PETS_BY_TAGS: String = "/pet/findByTags" const val PATH_GET_PET_BY_ID: String = "/pet/{petId}" + const val PATH_LIST_ALL_PETS_PAGINATED: String = "/pet/paginated/all" + const val PATH_LIST_PETS_BY_ID_PAGINATED: String = "/pet/paginated/pathOnly" + const val PATH_LIST_PETS_BY_OWNER_PAGINATED: String = "/pet/paginated/{ownerId}" + const val PATH_LIST_PETS_MIXED_PARAMS: String = "/pet/paginated/mixed" + const val PATH_LIST_PETS_MULTIPLE_PARAMS: String = "/pet/paginated/multiParam" + const val PATH_LIST_PETS_NO_PAGINATION: String = "/pet/paginated/noPagination" + const val PATH_LIST_PETS_PARTIAL_PAGINATION: String = "/pet/paginated/partialParams" + const val PATH_LIST_PETS_WITH_FILTER_PAGINATED: String = "/pet/paginated/withParams" + const val PATH_LIST_PETS_WITH_HEADER_SIZE: String = "/pet/paginated/headerSize" const val PATH_UPDATE_PET: String = "/pet" const val PATH_UPDATE_PET_WITH_FORM: String = "/pet/{petId}" const val PATH_UPLOAD_FILE: String = "/pet/{petId}/uploadImage" diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt index 66314ad03c2b..7513f4fadf58 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt @@ -1,6 +1,7 @@ package org.openapitools.api import org.openapitools.model.ModelApiResponse +import org.springframework.data.domain.Pageable import org.openapitools.model.Pet import org.springframework.http.HttpStatus import org.springframework.http.MediaType @@ -55,6 +56,90 @@ interface PetApiDelegate { exchange: org.springframework.web.server.ServerWebExchange): ResponseEntity + /** + * @see PetApi#listAllPetsPaginated + */ + fun listAllPetsPaginated(exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsByIdPaginated + */ + fun listPetsByIdPaginated(petId: kotlin.Long, + xRequestID: kotlin.String?, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsByOwnerPaginated + */ + fun listPetsByOwnerPaginated(ownerId: kotlin.Long, + includeAdopted: kotlin.Boolean, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsMixedParams + */ + fun listPetsMixedParams(categoryId: kotlin.Long, + authorization: kotlin.String?, + xTenantID: kotlin.String?, + status: kotlin.String?, + includeInactive: kotlin.Boolean?, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsMultipleParams + */ + fun listPetsMultipleParams(name: kotlin.String?, + minAge: kotlin.Int?, + maxAge: kotlin.Int?, + tags: kotlin.collections.List?, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsNoPagination + */ + fun listPetsNoPagination(status: kotlin.String?, + page: kotlin.Int?, + size: kotlin.Int?, + sort: kotlin.String?, + exchange: org.springframework.web.server.ServerWebExchange): ResponseEntity> + + + /** + * @see PetApi#listPetsPartialPagination + */ + fun listPetsPartialPagination(status: kotlin.String?, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsWithFilterPaginated + */ + fun listPetsWithFilterPaginated(status: kotlin.String?, + name: kotlin.String?, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + + /** + * @see PetApi#listPetsWithHeaderSize + */ + fun listPetsWithHeaderSize(size: kotlin.String?, + category: kotlin.String?, + exchange: org.springframework.web.server.ServerWebExchange, + pageable: Pageable): ResponseEntity> + + /** * @see PetApi#updatePet */ diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt index d30df48a2e47..d5df7f08f2c9 100644 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt +++ b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -6,6 +6,7 @@ package org.openapitools.api import org.openapitools.model.ModelApiResponse +import org.springframework.data.domain.Pageable import org.openapitools.model.Pet import io.swagger.annotations.Api import io.swagger.annotations.ApiOperation @@ -152,6 +153,223 @@ interface PetApi { ): ResponseEntity + @ApiOperation( + value = "List all pets with pagination (only pagination params)", + nickname = "listAllPetsPaginated", + notes = "Tests x-spring-paginated with ONLY page/size/sort params that will be removed", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/all" + value = [PATH_LIST_ALL_PETS_PAGINATED], + produces = ["application/json"] + ) + fun listAllPetsPaginated(@ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable): ResponseEntity> + + + @ApiOperation( + value = "List pets with path and header params only", + nickname = "listPetsByIdPaginated", + notes = "Tests x-spring-paginated with no query params except pagination", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/pathOnly" + value = [PATH_LIST_PETS_BY_ID_PAGINATED], + produces = ["application/json"] + ) + fun listPetsByIdPaginated( + @ApiParam(value = "Pet ID", required = true) @PathVariable("petId") petId: kotlin.Long, + @ApiParam(value = "Request ID for tracing") @RequestHeader(value = "X-Request-ID", required = false) xRequestID: kotlin.String?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + + @ApiOperation( + value = "List pets by owner with pagination", + nickname = "listPetsByOwnerPaginated", + notes = "Tests x-spring-paginated with path param + query params", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/{ownerId}" + value = [PATH_LIST_PETS_BY_OWNER_PAGINATED], + produces = ["application/json"] + ) + fun listPetsByOwnerPaginated( + @ApiParam(value = "Owner ID - will be kept", required = true) @PathVariable("ownerId") ownerId: kotlin.Long, + @ApiParam(value = "Include adopted pets - will be kept", defaultValue = "false") @Valid @RequestParam(value = "includeAdopted", required = false, defaultValue = "false") includeAdopted: kotlin.Boolean, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + + @ApiOperation( + value = "Mixed params - path, header, query, and pagination", + nickname = "listPetsMixedParams", + notes = "Comprehensive test with all parameter types", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/mixed" + value = [PATH_LIST_PETS_MIXED_PARAMS], + produces = ["application/json"] + ) + fun listPetsMixedParams( + @ApiParam(value = "Category ID", required = true) @PathVariable("categoryId") categoryId: kotlin.Long, + @ApiParam(value = "Authorization header") @RequestHeader(value = "Authorization", required = false) authorization: kotlin.String?, + @ApiParam(value = "Tenant ID") @RequestHeader(value = "X-Tenant-ID", required = false) xTenantID: kotlin.String?, + @ApiParam(value = "Status filter") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(value = "Include inactive pets") @Valid @RequestParam(value = "includeInactive", required = false) includeInactive: kotlin.Boolean?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + + @ApiOperation( + value = "List pets with many query params", + nickname = "listPetsMultipleParams", + notes = "Tests x-spring-paginated removes only page/size/sort", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/multiParam" + value = [PATH_LIST_PETS_MULTIPLE_PARAMS], + produces = ["application/json"] + ) + fun listPetsMultipleParams( + @ApiParam(value = "Filter by name - will be kept") @Valid @RequestParam(value = "name", required = false) name: kotlin.String?, + @ApiParam(value = "Minimum age - will be kept") @Valid @RequestParam(value = "minAge", required = false) minAge: kotlin.Int?, + @ApiParam(value = "Maximum age - will be kept") @Valid @RequestParam(value = "maxAge", required = false) maxAge: kotlin.Int?, + @ApiParam(value = "Filter by tags - will be kept") @Valid @RequestParam(value = "tags", required = false) tags: kotlin.collections.List?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + + @ApiOperation( + value = "List pets WITHOUT x-spring-paginated", + nickname = "listPetsNoPagination", + notes = "Tests that operations without x-spring-paginated keep all params", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/noPagination" + value = [PATH_LIST_PETS_NO_PAGINATION], + produces = ["application/json"] + ) + fun listPetsNoPagination( + @ApiParam(value = "Filter by status") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(value = "Page number - will be KEPT (no x-spring-paginated)") @Valid @RequestParam(value = "page", required = false) page: kotlin.Int?, + @ApiParam(value = "Page size - will be KEPT (no x-spring-paginated)") @Valid @RequestParam(value = "size", required = false) size: kotlin.Int?, + @ApiParam(value = "Sort order - will be KEPT (no x-spring-paginated)") @Valid @RequestParam(value = "sort", required = false) sort: kotlin.String?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest + ): ResponseEntity> + + + @ApiOperation( + value = "List pets with only some pagination params", + nickname = "listPetsPartialPagination", + notes = "Tests x-spring-paginated with only page and size (no sort)", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/partialParams" + value = [PATH_LIST_PETS_PARTIAL_PAGINATION], + produces = ["application/json"] + ) + fun listPetsPartialPagination( + @ApiParam(value = "Filter by status - will be kept") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + + @ApiOperation( + value = "List pets with filtering and pagination", + nickname = "listPetsWithFilterPaginated", + notes = "Tests x-spring-paginated with regular params + pagination params", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/withParams" + value = [PATH_LIST_PETS_WITH_FILTER_PAGINATED], + produces = ["application/json"] + ) + fun listPetsWithFilterPaginated( + @ApiParam(value = "Filter by status - will be kept", allowableValues = "available, pending, sold") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, + @ApiParam(value = "Filter by name - will be kept") @Valid @RequestParam(value = "name", required = false) name: kotlin.String?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + + @ApiOperation( + value = "List pets with header param named 'size'", + nickname = "listPetsWithHeaderSize", + notes = "Tests that header param 'size' is preserved while query param 'size' is removed", + response = Pet::class, + responseContainer = "List" + ) + @ApiResponses( + value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List")] + ) + @RequestMapping( + method = [RequestMethod.GET], + // "/pet/paginated/headerSize" + value = [PATH_LIST_PETS_WITH_HEADER_SIZE], + produces = ["application/json"] + ) + fun listPetsWithHeaderSize( + @ApiParam(value = "Size header - must NOT be removed (different from query param)") @RequestHeader(value = "size", required = false) size: kotlin.String?, + @ApiParam(value = "Filter by category - will be kept") @Valid @RequestParam(value = "category", required = false) category: kotlin.String?, + @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, + @ApiParam(hidden = true) pageable: Pageable + ): ResponseEntity> + + @ApiOperation( value = "Update an existing pet", nickname = "updatePet", @@ -227,6 +445,15 @@ interface PetApi { const val PATH_FIND_PETS_BY_STATUS: String = "/pet/findByStatus" const val PATH_FIND_PETS_BY_TAGS: String = "/pet/findByTags" const val PATH_GET_PET_BY_ID: String = "/pet/{petId}" + const val PATH_LIST_ALL_PETS_PAGINATED: String = "/pet/paginated/all" + const val PATH_LIST_PETS_BY_ID_PAGINATED: String = "/pet/paginated/pathOnly" + const val PATH_LIST_PETS_BY_OWNER_PAGINATED: String = "/pet/paginated/{ownerId}" + const val PATH_LIST_PETS_MIXED_PARAMS: String = "/pet/paginated/mixed" + const val PATH_LIST_PETS_MULTIPLE_PARAMS: String = "/pet/paginated/multiParam" + const val PATH_LIST_PETS_NO_PAGINATION: String = "/pet/paginated/noPagination" + const val PATH_LIST_PETS_PARTIAL_PAGINATION: String = "/pet/paginated/partialParams" + const val PATH_LIST_PETS_WITH_FILTER_PAGINATED: String = "/pet/paginated/withParams" + const val PATH_LIST_PETS_WITH_HEADER_SIZE: String = "/pet/paginated/headerSize" const val PATH_UPDATE_PET: String = "/pet" const val PATH_UPDATE_PET_WITH_FORM: String = "/pet/{petId}" const val PATH_UPLOAD_FILE: String = "/pet/{petId}/uploadImage" From 3331ddcb61977729bdf9937cc044b877788e4277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 00:25:19 +0100 Subject: [PATCH 06/24] add samples. use Pageable only for server-side --- .../languages/KotlinSpringServerCodegen.java | 54 ++++++++++--------- .../libraries/spring-boot/pom-sb3.mustache | 4 ++ .../libraries/spring-boot/pom.mustache | 4 ++ 3 files changed, 38 insertions(+), 24 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 bc162046c86c..9731be290081 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 @@ -886,10 +886,14 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera * - Removes the default Spring Data Web pagination query parameters (page, size, sort) * - Adds appropriate imports (Pageable, ApiIgnore for springfox, ParameterObject for springdoc) * + * Note: x-spring-paginated is ONLY applied for server-side libraries (spring-boot). + * Client libraries (spring-cloud, spring-declarative-http-interface) need actual query parameters + * to send over HTTP, so the extension is ignored for them. + * * Parameter ordering in generated methods: * 1. Regular OpenAPI parameters (allParams) * 2. Optional HttpServletRequest/ServerWebExchange (if includeHttpRequestContext is enabled) - * 3. Pageable parameter (if x-spring-paginated is true) + * 3. Pageable parameter (if x-spring-paginated is true and library is spring-boot) * * This implementation mirrors the behavior in SpringCodegen for consistency. * @@ -901,34 +905,36 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera */ @Override public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) { - // add Pageable import only if x-spring-paginated explicitly used - // this allows to use a custom Pageable schema without importing Spring Pageable. - if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-spring-paginated"))) { - importMapping.putIfAbsent("Pageable", "org.springframework.data.domain.Pageable"); - } - CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers); - - // add org.springframework.data.domain.Pageable import when needed - if (codegenOperation.vendorExtensions.containsKey("x-spring-paginated")) { - codegenOperation.imports.add("Pageable"); - if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) { - codegenOperation.imports.add("ApiIgnore"); - } - if (DocumentationProvider.SPRINGDOC.equals(getDocumentationProvider())) { - codegenOperation.imports.add("ParameterObject"); + // Only process x-spring-paginated for server-side libraries (spring-boot) + // Client libraries (spring-cloud, spring-declarative-http-interface) need actual query parameters for HTTP requests + if (SPRING_BOOT.equals(library)) { + // add Pageable import only if x-spring-paginated explicitly used AND it's a server library + // this allows to use a custom Pageable schema without importing Spring Pageable. + if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-spring-paginated"))) { + importMapping.putIfAbsent("Pageable", "org.springframework.data.domain.Pageable"); } - // #8315 Spring Data Web default query params recognized by Pageable - List defaultPageableQueryParams = new ArrayList<>( - Arrays.asList("page", "size", "sort") - ); + // add org.springframework.data.domain.Pageable import when needed (server libraries only) + if (codegenOperation.vendorExtensions.containsKey("x-spring-paginated")) { + codegenOperation.imports.add("Pageable"); + if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) { + codegenOperation.imports.add("ApiIgnore"); + } + if (DocumentationProvider.SPRINGDOC.equals(getDocumentationProvider())) { + codegenOperation.imports.add("ParameterObject"); + } - // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used - codegenOperation.queryParams.removeIf(param -> defaultPageableQueryParams.contains(param.baseName)); - codegenOperation.allParams.removeIf(param -> param.isQueryParam && defaultPageableQueryParams.contains(param.baseName)); - } + // #8315 Spring Data Web default query params recognized by Pageable + List defaultPageableQueryParams = new ArrayList<>( + Arrays.asList("page", "size", "sort") + ); + // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used + codegenOperation.queryParams.removeIf(param -> defaultPageableQueryParams.contains(param.baseName)); + codegenOperation.allParams.removeIf(param -> param.isQueryParam && defaultPageableQueryParams.contains(param.baseName)); + } + } return codegenOperation; } diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom-sb3.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom-sb3.mustache index a933ddd54863..79b278b33217 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom-sb3.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom-sb3.mustache @@ -129,6 +129,10 @@ kotlinx-coroutines-reactor ${kotlinx-coroutines.version} {{/reactive}} + + org.springframework.data + spring-data-commons + {{#springDocDocumentationProvider}} {{#useSwaggerUI}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache index 76dfa9767896..1aaf9f6158ec 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache @@ -116,6 +116,10 @@ kotlinx-coroutines-reactor ${kotlinx-coroutines.version} {{/reactive}} + + org.springframework.data + spring-data-commons + {{#springDocDocumentationProvider}} {{#useSwaggerUI}} From af87e8b5691edb276c060da9c20438b45df395d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 00:50:39 +0100 Subject: [PATCH 07/24] add support for auto-detecting x-spring-paginated in Spring Boot operations --- .../languages/KotlinSpringServerCodegen.java | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 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 9731be290081..be702abe78ab 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 @@ -45,6 +45,7 @@ import java.net.URL; import java.util.*; import java.util.regex.Matcher; +import java.util.stream.Collectors; import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; import static org.openapitools.codegen.utils.StringUtils.camelize; @@ -95,6 +96,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen public static final String REQUEST_MAPPING_OPTION = "requestMappingMode"; public static final String USE_REQUEST_MAPPING_ON_CONTROLLER = "useRequestMappingOnController"; public static final String USE_REQUEST_MAPPING_ON_INTERFACE = "useRequestMappingOnInterface"; + public static final String AUTO_X_SPRING_PAGINATED = "autoXSpringPaginated"; @Getter public enum DeclarativeInterfaceReactiveMode { @@ -158,6 +160,7 @@ public String getDescription() { @Setter private boolean beanQualifiers = false; @Setter private DeclarativeInterfaceReactiveMode declarativeInterfaceReactiveMode = DeclarativeInterfaceReactiveMode.coroutines; @Setter private boolean useResponseEntity = true; + @Setter private boolean autoXSpringPaginated = false; @Getter @Setter protected boolean useSpringBoot3 = false; @@ -251,6 +254,7 @@ public KotlinSpringServerCodegen() { addOption(X_KOTLIN_IMPLEMENTS_FIELDS_SKIP, "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"); addOption(SCHEMA_IMPLEMENTS, "A map of single interface or a list of interfaces per schema name that should be implemented (serves similar purpose as `x-kotlin-implements`, but is fully decoupled from the api spec). Example: yaml `schemaImplements: {Pet: com.some.pack.WithId, Category: [com.some.pack.CategoryInterface], Dog: [com.some.pack.Canine, com.some.pack.OtherInterface]}` implements interfaces in schemas `Pet` (interface `com.some.pack.WithId`), `Category` (interface `com.some.pack.CategoryInterface`), `Dog`(interfaces `com.some.pack.Canine`, `com.some.pack.OtherInterface`)", "empty map"); addOption(SCHEMA_IMPLEMENTS_FIELDS, "A map of single field or a list of fields per schema name that should be prepended with `override` (serves similar purpose as `x-kotlin-implements-fields`, but is fully decoupled from the api spec). Example: yaml `schemaImplementsFields: {Pet: id, Category: [name, id], Dog: [bark, breed]}` marks fields to be prepended with `override` in schemas `Pet` (field `id`), `Category` (fields `name`, `id`) and `Dog` (fields `bark`, `breed`)", "empty map"); + addSwitch(AUTO_X_SPRING_PAGINATED, "Automatically add x-spring-paginated to operations that have 'page', 'size', and 'sort' query parameters. When enabled, operations with all three parameters will have Pageable support automatically applied. Operations with x-spring-paginated explicitly set to false will not be auto-detected.", autoXSpringPaginated); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); supportedLibraries.put(SPRING_CLOUD_LIBRARY, "Spring-Cloud-Feign client with Spring-Boot auto-configured settings."); @@ -655,6 +659,10 @@ public void processOpts() { if (additionalProperties.containsKey(USE_TAGS)) { this.setUseTags(Boolean.parseBoolean(additionalProperties.get(USE_TAGS).toString())); } + if (additionalProperties.containsKey(AUTO_X_SPRING_PAGINATED) && library.equals(SPRING_BOOT)) { + this.setAutoXSpringPaginated(convertPropertyToBoolean(AUTO_X_SPRING_PAGINATED)); + } + writePropertyBack(AUTO_X_SPRING_PAGINATED, autoXSpringPaginated); if (isUseSpringBoot3()) { if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) { throw new IllegalArgumentException(DocumentationProvider.SPRINGFOX.getPropertyName() + " is not supported with Spring Boot > 3.x"); @@ -886,6 +894,12 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera * - Removes the default Spring Data Web pagination query parameters (page, size, sort) * - Adds appropriate imports (Pageable, ApiIgnore for springfox, ParameterObject for springdoc) * + * Auto-detection (when autoXSpringPaginated is enabled): + * - Automatically detects operations with 'page', 'size', and 'sort' query parameters (case-sensitive) + * - Applies x-spring-paginated behavior to these operations automatically + * - Respects manual x-spring-paginated: false setting (manual override takes precedence) + * - Only applies when library is spring-boot + * * Note: x-spring-paginated is ONLY applied for server-side libraries (spring-boot). * Client libraries (spring-cloud, spring-declarative-http-interface) need actual query parameters * to send over HTTP, so the extension is ignored for them. @@ -905,7 +919,33 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera */ @Override public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) { + // #8315 Spring Data Web default query params recognized by Pageable + List defaultPageableQueryParams = Arrays.asList("page", "size", "sort"); + CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers); + + // Auto-detect pagination parameters and add x-spring-paginated if autoXSpringPaginated is enabled + // Only for spring-boot library, respect manual x-spring-paginated: false setting + if (SPRING_BOOT.equals(library) && autoXSpringPaginated) { + // Check if x-spring-paginated is not explicitly set to false + if (operation.getExtensions() == null || !Boolean.FALSE.equals(operation.getExtensions().get("x-spring-paginated"))) { + // Check if operation has all three pagination query parameters (case-sensitive) + boolean hasParamsForPageable = codegenOperation.queryParams.stream() + .map(p -> p.baseName) + .collect(Collectors.toSet()) + .containsAll(defaultPageableQueryParams); + + if (hasParamsForPageable) { + // Automatically add x-spring-paginated to the operation + if (operation.getExtensions() == null) { + operation.setExtensions(new HashMap<>()); + } + operation.getExtensions().put("x-spring-paginated", Boolean.TRUE); + codegenOperation.vendorExtensions.put("x-spring-paginated", Boolean.TRUE); + } + } + } + // Only process x-spring-paginated for server-side libraries (spring-boot) // Client libraries (spring-cloud, spring-declarative-http-interface) need actual query parameters for HTTP requests if (SPRING_BOOT.equals(library)) { @@ -925,11 +965,6 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation codegenOperation.imports.add("ParameterObject"); } - // #8315 Spring Data Web default query params recognized by Pageable - List defaultPageableQueryParams = new ArrayList<>( - Arrays.asList("page", "size", "sort") - ); - // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used codegenOperation.queryParams.removeIf(param -> defaultPageableQueryParams.contains(param.baseName)); codegenOperation.allParams.removeIf(param -> param.isQueryParam && defaultPageableQueryParams.contains(param.baseName)); From f646cd213dcc8356072af5e383894b9a98fd138e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 00:56:18 +0100 Subject: [PATCH 08/24] fix maven dependencies import --- samples/server/petstore/kotlin-spring-default/pom.xml | 4 ++++ .../petstore/kotlin-springboot-3-no-response-entity/pom.xml | 4 ++++ samples/server/petstore/kotlin-springboot-3/pom.xml | 4 ++++ .../petstore/kotlin-springboot-additionalproperties/pom.xml | 4 ++++ .../petstore/kotlin-springboot-bigdecimal-default/pom.xml | 4 ++++ .../petstore/kotlin-springboot-delegate-nodefaults/pom.xml | 4 ++++ samples/server/petstore/kotlin-springboot-delegate/pom.xml | 4 ++++ .../pom.xml | 4 ++++ .../server/petstore/kotlin-springboot-integer-enum/pom.xml | 4 ++++ .../server/petstore/kotlin-springboot-modelMutable/pom.xml | 4 ++++ .../kotlin-springboot-multipart-request-model/pom.xml | 4 ++++ .../kotlin-springboot-no-response-entity-delegate/pom.xml | 4 ++++ .../petstore/kotlin-springboot-no-response-entity/pom.xml | 4 ++++ .../petstore/kotlin-springboot-reactive-without-flow/pom.xml | 4 ++++ samples/server/petstore/kotlin-springboot-reactive/pom.xml | 4 ++++ .../server/petstore/kotlin-springboot-request-cookie/pom.xml | 4 ++++ .../server/petstore/kotlin-springboot-source-swagger1/pom.xml | 4 ++++ .../server/petstore/kotlin-springboot-source-swagger2/pom.xml | 4 ++++ samples/server/petstore/kotlin-springboot-springfox/pom.xml | 4 ++++ .../petstore/kotlin-springboot-x-kotlin-implements/pom.xml | 4 ++++ samples/server/petstore/kotlin-springboot/pom.xml | 4 ++++ 21 files changed, 84 insertions(+) diff --git a/samples/server/petstore/kotlin-spring-default/pom.xml b/samples/server/petstore/kotlin-spring-default/pom.xml index ed6a78fd3ffe..76ef64f955da 100644 --- a/samples/server/petstore/kotlin-spring-default/pom.xml +++ b/samples/server/petstore/kotlin-spring-default/pom.xml @@ -86,6 +86,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-3-no-response-entity/pom.xml b/samples/server/petstore/kotlin-springboot-3-no-response-entity/pom.xml index 3c52a401bf8a..3844d9e01f44 100644 --- a/samples/server/petstore/kotlin-springboot-3-no-response-entity/pom.xml +++ b/samples/server/petstore/kotlin-springboot-3-no-response-entity/pom.xml @@ -98,6 +98,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-3/pom.xml b/samples/server/petstore/kotlin-springboot-3/pom.xml index 3c52a401bf8a..3844d9e01f44 100644 --- a/samples/server/petstore/kotlin-springboot-3/pom.xml +++ b/samples/server/petstore/kotlin-springboot-3/pom.xml @@ -98,6 +98,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-additionalproperties/pom.xml b/samples/server/petstore/kotlin-springboot-additionalproperties/pom.xml index 3c52a401bf8a..3844d9e01f44 100644 --- a/samples/server/petstore/kotlin-springboot-additionalproperties/pom.xml +++ b/samples/server/petstore/kotlin-springboot-additionalproperties/pom.xml @@ -98,6 +98,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-bigdecimal-default/pom.xml b/samples/server/petstore/kotlin-springboot-bigdecimal-default/pom.xml index ed6a78fd3ffe..76ef64f955da 100644 --- a/samples/server/petstore/kotlin-springboot-bigdecimal-default/pom.xml +++ b/samples/server/petstore/kotlin-springboot-bigdecimal-default/pom.xml @@ -86,6 +86,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-delegate-nodefaults/pom.xml b/samples/server/petstore/kotlin-springboot-delegate-nodefaults/pom.xml index b041f6c83f6e..c7a557207ccc 100644 --- a/samples/server/petstore/kotlin-springboot-delegate-nodefaults/pom.xml +++ b/samples/server/petstore/kotlin-springboot-delegate-nodefaults/pom.xml @@ -99,6 +99,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-delegate/pom.xml b/samples/server/petstore/kotlin-springboot-delegate/pom.xml index ed6a78fd3ffe..76ef64f955da 100644 --- a/samples/server/petstore/kotlin-springboot-delegate/pom.xml +++ b/samples/server/petstore/kotlin-springboot-delegate/pom.xml @@ -86,6 +86,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/pom.xml b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/pom.xml index 1e85d34a2f9e..9e5b5f9d5877 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/pom.xml +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/pom.xml @@ -97,6 +97,10 @@ kotlinx-coroutines-reactor ${kotlinx-coroutines.version} + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-integer-enum/pom.xml b/samples/server/petstore/kotlin-springboot-integer-enum/pom.xml index 77a9c03660db..67af2523dcb8 100644 --- a/samples/server/petstore/kotlin-springboot-integer-enum/pom.xml +++ b/samples/server/petstore/kotlin-springboot-integer-enum/pom.xml @@ -98,6 +98,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-modelMutable/pom.xml b/samples/server/petstore/kotlin-springboot-modelMutable/pom.xml index ed6a78fd3ffe..76ef64f955da 100644 --- a/samples/server/petstore/kotlin-springboot-modelMutable/pom.xml +++ b/samples/server/petstore/kotlin-springboot-modelMutable/pom.xml @@ -86,6 +86,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-multipart-request-model/pom.xml b/samples/server/petstore/kotlin-springboot-multipart-request-model/pom.xml index ed6a78fd3ffe..76ef64f955da 100644 --- a/samples/server/petstore/kotlin-springboot-multipart-request-model/pom.xml +++ b/samples/server/petstore/kotlin-springboot-multipart-request-model/pom.xml @@ -86,6 +86,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/pom.xml b/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/pom.xml index cab717f26a33..7a6726d7bbfd 100644 --- a/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/pom.xml +++ b/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/pom.xml @@ -85,6 +85,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-no-response-entity/pom.xml b/samples/server/petstore/kotlin-springboot-no-response-entity/pom.xml index cab717f26a33..7a6726d7bbfd 100644 --- a/samples/server/petstore/kotlin-springboot-no-response-entity/pom.xml +++ b/samples/server/petstore/kotlin-springboot-no-response-entity/pom.xml @@ -85,6 +85,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-reactive-without-flow/pom.xml b/samples/server/petstore/kotlin-springboot-reactive-without-flow/pom.xml index 80ae9216e1e3..39afc668db31 100644 --- a/samples/server/petstore/kotlin-springboot-reactive-without-flow/pom.xml +++ b/samples/server/petstore/kotlin-springboot-reactive-without-flow/pom.xml @@ -97,6 +97,10 @@ kotlinx-coroutines-reactor ${kotlinx-coroutines.version} + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-reactive/pom.xml b/samples/server/petstore/kotlin-springboot-reactive/pom.xml index 80ae9216e1e3..39afc668db31 100644 --- a/samples/server/petstore/kotlin-springboot-reactive/pom.xml +++ b/samples/server/petstore/kotlin-springboot-reactive/pom.xml @@ -97,6 +97,10 @@ kotlinx-coroutines-reactor ${kotlinx-coroutines.version} + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-request-cookie/pom.xml b/samples/server/petstore/kotlin-springboot-request-cookie/pom.xml index fb11e4866dec..797865c697a9 100644 --- a/samples/server/petstore/kotlin-springboot-request-cookie/pom.xml +++ b/samples/server/petstore/kotlin-springboot-request-cookie/pom.xml @@ -99,6 +99,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-source-swagger1/pom.xml b/samples/server/petstore/kotlin-springboot-source-swagger1/pom.xml index 31f4899ccbe3..07c34bb1288e 100644 --- a/samples/server/petstore/kotlin-springboot-source-swagger1/pom.xml +++ b/samples/server/petstore/kotlin-springboot-source-swagger1/pom.xml @@ -87,6 +87,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-source-swagger2/pom.xml b/samples/server/petstore/kotlin-springboot-source-swagger2/pom.xml index 2c1eb5b4ae8a..b8f74802da03 100644 --- a/samples/server/petstore/kotlin-springboot-source-swagger2/pom.xml +++ b/samples/server/petstore/kotlin-springboot-source-swagger2/pom.xml @@ -87,6 +87,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-springfox/pom.xml b/samples/server/petstore/kotlin-springboot-springfox/pom.xml index c733bf0da18b..789f094be1c1 100644 --- a/samples/server/petstore/kotlin-springboot-springfox/pom.xml +++ b/samples/server/petstore/kotlin-springboot-springfox/pom.xml @@ -87,6 +87,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/pom.xml b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/pom.xml index 067cb2bbd025..abd0f31c98ca 100644 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/pom.xml +++ b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/pom.xml @@ -86,6 +86,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + diff --git a/samples/server/petstore/kotlin-springboot/pom.xml b/samples/server/petstore/kotlin-springboot/pom.xml index cab717f26a33..7a6726d7bbfd 100644 --- a/samples/server/petstore/kotlin-springboot/pom.xml +++ b/samples/server/petstore/kotlin-springboot/pom.xml @@ -85,6 +85,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.data + spring-data-commons + From 744012d44458ffe565ef5586615e1345dfd433e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 01:10:56 +0100 Subject: [PATCH 09/24] add unit tests --- .../languages/KotlinSpringServerCodegen.java | 2 +- .../spring/KotlinSpringServerCodegenTest.java | 309 ++++++++++++++++++ .../3_0/spring/petstore-auto-paginated.yaml | 267 +++++++++++++++ 3 files changed, 577 insertions(+), 1 deletion(-) create mode 100644 modules/openapi-generator/src/test/resources/3_0/spring/petstore-auto-paginated.yaml 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 be702abe78ab..0c08a9e9484a 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 @@ -956,7 +956,7 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation } // add org.springframework.data.domain.Pageable import when needed (server libraries only) - if (codegenOperation.vendorExtensions.containsKey("x-spring-paginated")) { + if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-spring-paginated"))) { codegenOperation.imports.add("Pageable"); if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) { codegenOperation.imports.add("ApiIgnore"); 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 1ab6a7ecb99b..8bae29e43d82 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 @@ -4023,4 +4023,313 @@ private Map generateFromContract( return generator.opts(input).generate().stream() .collect(Collectors.toMap(File::getName, Function.identity())); } + + // ========== AUTO X-SPRING-PAGINATED TESTS ========== + + @Test + public void autoXSpringPaginatedDetectsAllThreeParams() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation with all three params (page, size, sort) should have Pageable auto-detected + assertFileContains(petApi.toPath(), "fun findPetsWithAutoDetect("); + assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); + + // Extract findPetsWithAutoDetect method + int methodStart = content.indexOf("fun findPetsWithAutoDetect("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + // Should have pageable parameter + Assert.assertTrue(methodSignature.contains("pageable: Pageable"), + "findPetsWithAutoDetect should have pageable parameter when autoXSpringPaginated is enabled"); + + // Should NOT have page, size, sort query params (they should be removed) + Assert.assertFalse(methodSignature.contains("page:"), + "page query param should be removed when pageable is added"); + Assert.assertFalse(methodSignature.contains("size:"), + "size query param should be removed when pageable is added"); + Assert.assertFalse(methodSignature.contains("sort:"), + "sort query param should be removed when pageable is added"); + + // Should still have the status parameter + Assert.assertTrue(methodSignature.contains("status:"), + "status parameter should remain"); + } + + @Test + public void autoXSpringPaginatedNoDetectionWhenMissingPage() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation missing 'page' param should NOT have Pageable + int methodStart = content.indexOf("fun findPetsMissingPage("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "findPetsMissingPage should NOT have pageable when 'page' param is missing"); + + // Should still have the other params + Assert.assertTrue(methodSignature.contains("size:"), + "size param should remain"); + Assert.assertTrue(methodSignature.contains("sort:"), + "sort param should remain"); + } + + @Test + public void autoXSpringPaginatedNoDetectionWhenMissingSize() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation missing 'size' param should NOT have Pageable + int methodStart = content.indexOf("fun findPetsMissingSize("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "findPetsMissingSize should NOT have pageable when 'size' param is missing"); + + // Should still have the other params + Assert.assertTrue(methodSignature.contains("page:"), + "page param should remain"); + Assert.assertTrue(methodSignature.contains("sort:"), + "sort param should remain"); + } + + @Test + public void autoXSpringPaginatedNoDetectionWhenMissingSort() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation missing 'sort' param should NOT have Pageable + int methodStart = content.indexOf("fun findPetsMissingSort("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "findPetsMissingSort should NOT have pageable when 'sort' param is missing"); + + // Should still have the other params + Assert.assertTrue(methodSignature.contains("page:"), + "page param should remain"); + Assert.assertTrue(methodSignature.contains("size:"), + "size param should remain"); + } + + @Test + public void autoXSpringPaginatedManualFalseTakesPrecedence() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation with x-spring-paginated: false should NOT have Pageable (manual override) + int methodStart = content.indexOf("fun findPetsManualFalse("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "findPetsManualFalse should NOT have pageable when x-spring-paginated is explicitly set to false"); + + // Should still have all three params + Assert.assertTrue(methodSignature.contains("page:"), + "page param should remain when x-spring-paginated: false"); + Assert.assertTrue(methodSignature.contains("size:"), + "size param should remain when x-spring-paginated: false"); + Assert.assertTrue(methodSignature.contains("sort:"), + "sort param should remain when x-spring-paginated: false"); + } + + @Test + public void autoXSpringPaginatedCaseSensitiveMatching() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation with Page, Size, Sort (capitalized) should NOT match + int methodStart = content.indexOf("fun findPetsCaseSensitive("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "findPetsCaseSensitive should NOT have pageable with capitalized param names (case-sensitive)"); + + // Should still have all three params with capital letters + Assert.assertTrue(methodSignature.contains("page:") || methodSignature.contains("Page:"), + "Page param should remain"); + } + + @Test + public void autoXSpringPaginatedOnlyForSpringBoot() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + // Test with spring-cloud library (should NOT auto-detect) + Map files = generateFromContract( + "src/test/resources/3_0/spring/petstore-auto-paginated.yaml", + additionalProperties, + new HashMap<>(), + configurator -> configurator.setLibrary("spring-cloud") + ); + + File petApi = files.get("PetApiClient.kt"); + if (petApi != null) { + String content = Files.readString(petApi.toPath()); + + // For spring-cloud, should NOT have Pageable even with auto-detect enabled + Assert.assertFalse(content.contains("pageable: Pageable"), + "spring-cloud library should NOT auto-detect pageable (needs actual query params for HTTP)"); + + // Should have all three query params + int methodStart = content.indexOf("fun findPetsWithAutoDetect("); + if (methodStart >= 0) { + int methodEnd = content.indexOf("): ", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertTrue(methodSignature.contains("page") || methodSignature.contains("@Query"), + "spring-cloud should keep query parameters"); + } + } + } + + @Test + public void autoXSpringPaginatedDisabledByDefault() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + // NOT setting AUTO_X_SPRING_PAGINATED (should default to false) + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Without AUTO_X_SPRING_PAGINATED, should NOT auto-detect + int methodStart = content.indexOf("fun findPetsWithAutoDetect("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "Should NOT have pageable when autoXSpringPaginated is not enabled (default: false)"); + + // Should have all three query params + Assert.assertTrue(methodSignature.contains("page:"), + "page param should remain when auto-detect is disabled"); + Assert.assertTrue(methodSignature.contains("size:"), + "size param should remain when auto-detect is disabled"); + Assert.assertTrue(methodSignature.contains("sort:"), + "sort param should remain when auto-detect is disabled"); + } + + @Test + public void autoXSpringPaginatedWorksWithManualTrue() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation with manual x-spring-paginated: true should still work + int methodStart = content.indexOf("fun findPetsManualTrue("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertTrue(methodSignature.contains("pageable: Pageable"), + "findPetsManualTrue should have pageable (manual x-spring-paginated: true)"); + + // Query params should be removed + Assert.assertFalse(methodSignature.contains("page:"), + "page param should be removed"); + Assert.assertFalse(methodSignature.contains("size:"), + "size param should be removed"); + Assert.assertFalse(methodSignature.contains("sort:"), + "sort param should be removed"); + } + + @Test + public void autoXSpringPaginatedNoParamsDoesNotDetect() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + additionalProperties.put(AUTO_X_SPRING_PAGINATED, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-auto-paginated.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Operation with no params should NOT have Pageable + int methodStart = content.indexOf("fun findPetsNoParams("); + int methodEnd = content.indexOf("): ResponseEntity", methodStart); + String methodSignature = content.substring(methodStart, methodEnd); + + Assert.assertFalse(methodSignature.contains("pageable: Pageable"), + "findPetsNoParams should NOT have pageable when there are no pagination params"); + } } + + diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-auto-paginated.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-auto-paginated.yaml new file mode 100644 index 000000000000..15228bab1ba0 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-auto-paginated.yaml @@ -0,0 +1,267 @@ +openapi: 3.0.1 +info: + title: OpenAPI Petstore - Auto Pagination Test + description: Test spec for auto x-spring-paginated detection + version: 1.0.0 +servers: + - url: http://petstore.swagger.io/v2 +tags: + - name: pet + description: Everything about your Pets +paths: + /pet/autoDetect: + get: + tags: + - pet + summary: Test auto-detection with all three params + description: Should auto-detect pagination params (page, size, sort) + operationId: findPetsWithAutoDetect + parameters: + - name: status + in: query + description: Status filter + schema: + type: string + - name: page + in: query + description: Page number + schema: + type: integer + default: 0 + - name: size + in: query + description: Page size + schema: + type: integer + default: 20 + - name: sort + in: query + description: Sort order + schema: + type: string + default: "id,asc" + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/missingPage: + get: + tags: + - pet + summary: Test with missing page param + description: Should NOT auto-detect (missing page) + operationId: findPetsMissingPage + parameters: + - name: size + in: query + description: Page size + schema: + type: integer + - name: sort + in: query + description: Sort order + schema: + type: string + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/missingSize: + get: + tags: + - pet + summary: Test with missing size param + description: Should NOT auto-detect (missing size) + operationId: findPetsMissingSize + parameters: + - name: page + in: query + description: Page number + schema: + type: integer + - name: sort + in: query + description: Sort order + schema: + type: string + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/missingSort: + get: + tags: + - pet + summary: Test with missing sort param + description: Should NOT auto-detect (missing sort) + operationId: findPetsMissingSort + parameters: + - name: page + in: query + description: Page number + schema: + type: integer + - name: size + in: query + description: Page size + schema: + type: integer + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/manualFalse: + get: + tags: + - pet + summary: Test manual x-spring-paginated false + description: Should NOT auto-detect (manual override to false) + operationId: findPetsManualFalse + x-spring-paginated: false + parameters: + - name: page + in: query + description: Page number + schema: + type: integer + - name: size + in: query + description: Page size + schema: + type: integer + - name: sort + in: query + description: Sort order + schema: + type: string + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/caseSensitive: + get: + tags: + - pet + summary: Test case-sensitive matching + description: Should NOT auto-detect (Page, Size, Sort with capitals) + operationId: findPetsCaseSensitive + parameters: + - name: Page + in: query + description: Page number (capital P) + schema: + type: integer + - name: Size + in: query + description: Page size (capital S) + schema: + type: integer + - name: Sort + in: query + description: Sort order (capital S) + schema: + type: string + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/manualTrue: + get: + tags: + - pet + summary: Test manual x-spring-paginated true + description: Should have pageable (manual x-spring-paginated true) + operationId: findPetsManualTrue + x-spring-paginated: true + parameters: + - name: status + in: query + description: Status filter + schema: + type: string + - name: page + in: query + description: Page number + schema: + type: integer + - name: size + in: query + description: Page size + schema: + type: integer + - name: sort + in: query + description: Sort order + schema: + type: string + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pet/noParams: + get: + tags: + - pet + summary: Test with no pagination params + description: Should NOT auto-detect (no pagination params) + operationId: findPetsNoParams + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' +components: + schemas: + Pet: + type: object + required: + - name + properties: + id: + type: integer + format: int64 + name: + type: string + status: + type: string + description: pet status in the store + From 35868280252a0a2541594a0ffd664445c8747ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 01:14:10 +0100 Subject: [PATCH 10/24] add support for vendor extension --- .../codegen/languages/KotlinSpringServerCodegen.java | 1 + 1 file changed, 1 insertion(+) 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 0c08a9e9484a..5fd5c2cf45c2 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 @@ -1224,6 +1224,7 @@ public List getSupportedVendorExtensions() { extensions.add(VendorExtension.X_MAXIMUM_MESSAGE); extensions.add(VendorExtension.X_KOTLIN_IMPLEMENTS); extensions.add(VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS); + extensions.add(VendorExtension.X_SPRING_PAGINATED); return extensions; } From 0ea92d1f3576ea6b08a54113da5a427edc16834a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 01:25:47 +0100 Subject: [PATCH 11/24] remove files --- .../kotlin/org/openapitools/api/PetApiTest.kt | 129 ------------------ .../org/openapitools/api/StoreApiTest.kt | 66 --------- .../org/openapitools/api/UserApiTest.kt | 124 ----------------- 3 files changed, 319 deletions(-) delete mode 100644 samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/PetApiTest.kt delete mode 100644 samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/StoreApiTest.kt delete mode 100644 samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/UserApiTest.kt diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/PetApiTest.kt b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/PetApiTest.kt deleted file mode 100644 index 4ee3b320cc3e..000000000000 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/PetApiTest.kt +++ /dev/null @@ -1,129 +0,0 @@ -package org.openapitools.api - -import org.openapitools.model.ModelApiResponse -import org.openapitools.model.Pet -import org.junit.jupiter.api.Test -import org.springframework.http.ResponseEntity - -class PetApiTest { - - private val service: PetApiService = PetApiServiceImpl() - private val api: PetApiController = PetApiController(service) - - /** - * To test PetApiController.addPet - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun addPetTest() { - val body: Pet = TODO() - val response: ResponseEntity = api.addPet(body) - - // TODO: test validations - } - - /** - * To test PetApiController.deletePet - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun deletePetTest() { - val petId: kotlin.Long = TODO() - val apiKey: kotlin.String? = TODO() - val response: ResponseEntity = api.deletePet(petId, apiKey) - - // TODO: test validations - } - - /** - * To test PetApiController.findPetsByStatus - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun findPetsByStatusTest() { - val status: kotlin.collections.List = TODO() - val response: ResponseEntity> = api.findPetsByStatus(status) - - // TODO: test validations - } - - /** - * To test PetApiController.findPetsByTags - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun findPetsByTagsTest() { - val tags: kotlin.collections.List = TODO() - val response: ResponseEntity> = api.findPetsByTags(tags) - - // TODO: test validations - } - - /** - * To test PetApiController.getPetById - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun getPetByIdTest() { - val petId: kotlin.Long = TODO() - val response: ResponseEntity = api.getPetById(petId) - - // TODO: test validations - } - - /** - * To test PetApiController.updatePet - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun updatePetTest() { - val body: Pet = TODO() - val response: ResponseEntity = api.updatePet(body) - - // TODO: test validations - } - - /** - * To test PetApiController.updatePetWithForm - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun updatePetWithFormTest() { - val petId: kotlin.Long = TODO() - val name: kotlin.String? = TODO() - val status: kotlin.String? = TODO() - val response: ResponseEntity = api.updatePetWithForm(petId, name, status) - - // TODO: test validations - } - - /** - * To test PetApiController.uploadFile - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun uploadFileTest() { - val petId: kotlin.Long = TODO() - val additionalMetadata: kotlin.String? = TODO() - val file: org.springframework.web.multipart.MultipartFile? = TODO() - val response: ResponseEntity = api.uploadFile(petId, additionalMetadata, file) - - // TODO: test validations - } -} diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/StoreApiTest.kt b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/StoreApiTest.kt deleted file mode 100644 index 69e269b03ef1..000000000000 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/StoreApiTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -package org.openapitools.api - -import org.openapitools.model.Order -import org.junit.jupiter.api.Test -import org.springframework.http.ResponseEntity - -class StoreApiTest { - - private val service: StoreApiService = StoreApiServiceImpl() - private val api: StoreApiController = StoreApiController(service) - - /** - * To test StoreApiController.deleteOrder - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun deleteOrderTest() { - val orderId: kotlin.String = TODO() - val response: ResponseEntity = api.deleteOrder(orderId) - - // TODO: test validations - } - - /** - * To test StoreApiController.getInventory - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun getInventoryTest() { - val response: ResponseEntity> = api.getInventory() - - // TODO: test validations - } - - /** - * To test StoreApiController.getOrderById - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun getOrderByIdTest() { - val orderId: kotlin.Long = TODO() - val response: ResponseEntity = api.getOrderById(orderId) - - // TODO: test validations - } - - /** - * To test StoreApiController.placeOrder - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun placeOrderTest() { - val body: Order = TODO() - val response: ResponseEntity = api.placeOrder(body) - - // TODO: test validations - } -} diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/UserApiTest.kt b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/UserApiTest.kt deleted file mode 100644 index eb20423da71c..000000000000 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/test/kotlin/org/openapitools/api/UserApiTest.kt +++ /dev/null @@ -1,124 +0,0 @@ -package org.openapitools.api - -import org.openapitools.model.User -import org.junit.jupiter.api.Test -import org.springframework.http.ResponseEntity - -class UserApiTest { - - private val service: UserApiService = UserApiServiceImpl() - private val api: UserApiController = UserApiController(service) - - /** - * To test UserApiController.createUser - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun createUserTest() { - val body: User = TODO() - val response: ResponseEntity = api.createUser(body) - - // TODO: test validations - } - - /** - * To test UserApiController.createUsersWithArrayInput - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun createUsersWithArrayInputTest() { - val body: kotlin.collections.List = TODO() - val response: ResponseEntity = api.createUsersWithArrayInput(body) - - // TODO: test validations - } - - /** - * To test UserApiController.createUsersWithListInput - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun createUsersWithListInputTest() { - val body: kotlin.collections.List = TODO() - val response: ResponseEntity = api.createUsersWithListInput(body) - - // TODO: test validations - } - - /** - * To test UserApiController.deleteUser - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun deleteUserTest() { - val username: kotlin.String = TODO() - val response: ResponseEntity = api.deleteUser(username) - - // TODO: test validations - } - - /** - * To test UserApiController.getUserByName - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun getUserByNameTest() { - val username: kotlin.String = TODO() - val response: ResponseEntity = api.getUserByName(username) - - // TODO: test validations - } - - /** - * To test UserApiController.loginUser - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun loginUserTest() { - val username: kotlin.String = TODO() - val password: kotlin.String = TODO() - val response: ResponseEntity = api.loginUser(username, password) - - // TODO: test validations - } - - /** - * To test UserApiController.logoutUser - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun logoutUserTest() { - val response: ResponseEntity = api.logoutUser() - - // TODO: test validations - } - - /** - * To test UserApiController.updateUser - * - * @throws ApiException - * if the Api call fails - */ - @Test - fun updateUserTest() { - val username: kotlin.String = TODO() - val body: User = TODO() - val response: ResponseEntity = api.updateUser(username, body) - - // TODO: test validations - } -} From 21f82d2b4fed405581801288fa1e27ce0d60930d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 01:33:14 +0100 Subject: [PATCH 12/24] fix samples --- .../libraries/spring-boot/buildGradle-sb3-Kts.mustache | 3 ++- .../libraries/spring-boot/buildGradleKts.mustache | 3 ++- samples/server/petstore/kotlin-spring-default/build.gradle.kts | 1 + .../kotlin-springboot-3-no-response-entity/build.gradle.kts | 1 + samples/server/petstore/kotlin-springboot-3/build.gradle.kts | 1 + .../kotlin-springboot-additionalproperties/build.gradle.kts | 1 + .../kotlin-springboot-bigdecimal-default/build.gradle.kts | 1 + .../kotlin-springboot-delegate-nodefaults/build.gradle.kts | 1 + .../petstore/kotlin-springboot-delegate/build.gradle.kts | 1 + .../build.gradle.kts | 1 + .../petstore/kotlin-springboot-integer-enum/build.gradle.kts | 1 + .../petstore/kotlin-springboot-modelMutable/build.gradle.kts | 1 + .../kotlin-springboot-multipart-request-model/build.gradle.kts | 1 + .../build.gradle.kts | 1 + .../kotlin-springboot-no-response-entity/build.gradle.kts | 1 + .../kotlin-springboot-reactive-without-flow/build.gradle.kts | 1 + .../petstore/kotlin-springboot-reactive/build.gradle.kts | 1 + .../petstore/kotlin-springboot-request-cookie/build.gradle.kts | 1 + .../kotlin-springboot-source-swagger1/build.gradle.kts | 1 + .../kotlin-springboot-source-swagger2/build.gradle.kts | 1 + .../petstore/kotlin-springboot-springfox/build.gradle.kts | 1 + .../kotlin-springboot-x-kotlin-implements/build.gradle.kts | 1 + samples/server/petstore/kotlin-springboot/build.gradle.kts | 1 + 23 files changed, 25 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache index 1cca74ad1ede..555c9c45757b 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache @@ -31,7 +31,8 @@ plugins { dependencies { {{#reactive}} val kotlinxCoroutinesVersion = "1.6.1" {{/reactive}} implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlin:kotlin-reflect"){{^reactive}} + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons"){{^reactive}} implementation("org.springframework.boot:spring-boot-starter-web"){{/reactive}}{{#reactive}} implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache index f3c3109f4e29..100976c80644 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -38,7 +38,8 @@ plugins { dependencies { {{#reactive}} val kotlinxCoroutinesVersion = "1.6.1" {{/reactive}} implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlin:kotlin-reflect"){{^reactive}} + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons"){{^reactive}} implementation("org.springframework.boot:spring-boot-starter-web"){{/reactive}}{{#reactive}} implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") diff --git a/samples/server/petstore/kotlin-spring-default/build.gradle.kts b/samples/server/petstore/kotlin-spring-default/build.gradle.kts index e956b616df71..9153b932e804 100644 --- a/samples/server/petstore/kotlin-spring-default/build.gradle.kts +++ b/samples/server/petstore/kotlin-spring-default/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") diff --git a/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts b/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts index 473c0162e0f4..19efbcc9ca07 100644 --- a/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts @@ -25,6 +25,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") diff --git a/samples/server/petstore/kotlin-springboot-3/build.gradle.kts b/samples/server/petstore/kotlin-springboot-3/build.gradle.kts index 473c0162e0f4..19efbcc9ca07 100644 --- a/samples/server/petstore/kotlin-springboot-3/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-3/build.gradle.kts @@ -25,6 +25,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") diff --git a/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts b/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts index 473c0162e0f4..19efbcc9ca07 100644 --- a/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts @@ -25,6 +25,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") diff --git a/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts b/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts index e956b616df71..9153b932e804 100644 --- a/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") diff --git a/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts b/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts index 8a3d16c5fad0..33c3634ee8dc 100644 --- a/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts @@ -25,6 +25,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("io.swagger.core.v3:swagger-annotations:2.2.0") diff --git a/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts b/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts index e956b616df71..9153b932e804 100644 --- a/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts index e78a961d4091..26783d8398f4 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { val kotlinxCoroutinesVersion = "1.6.1" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion") diff --git a/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts b/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts index 0caea597c84f..f5c38c84f3d2 100644 --- a/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts @@ -29,6 +29,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") diff --git a/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts b/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts index e956b616df71..9153b932e804 100644 --- a/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") diff --git a/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts b/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts index e956b616df71..9153b932e804 100644 --- a/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") diff --git a/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts b/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts index 3507e44d515a..63f5d8f6fe81 100644 --- a/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") diff --git a/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts b/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts index 3507e44d515a..63f5d8f6fe81 100644 --- a/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") diff --git a/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts b/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts index e2f66299c1f1..0318dbf63035 100644 --- a/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { val kotlinxCoroutinesVersion = "1.6.1" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion") diff --git a/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts b/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts index e2f66299c1f1..0318dbf63035 100644 --- a/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { val kotlinxCoroutinesVersion = "1.6.1" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion") diff --git a/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts b/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts index ebeee8407bcc..f2ae840a132b 100644 --- a/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts @@ -29,6 +29,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0") diff --git a/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts b/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts index 0e1a003d2859..28bae7b0e3d2 100644 --- a/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.webjars:swagger-ui:4.10.3") implementation("org.webjars:webjars-locator-core") diff --git a/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts b/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts index a024c20a2a9c..57d707185de1 100644 --- a/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.webjars:swagger-ui:4.10.3") implementation("org.webjars:webjars-locator-core") diff --git a/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts b/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts index a5e654a22c9f..44e3c1977252 100644 --- a/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("io.springfox:springfox-swagger2:2.9.2") implementation("org.webjars:swagger-ui:4.10.3") diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts index 10a80f14f0ff..8fa3f976d1a4 100644 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts @@ -36,6 +36,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("io.swagger:swagger-annotations:1.6.6") diff --git a/samples/server/petstore/kotlin-springboot/build.gradle.kts b/samples/server/petstore/kotlin-springboot/build.gradle.kts index 3507e44d515a..63f5d8f6fe81 100644 --- a/samples/server/petstore/kotlin-springboot/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot/build.gradle.kts @@ -32,6 +32,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") From b7864f477f211b25cf3ad0aa751f15bcba1ba865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 01:51:15 +0100 Subject: [PATCH 13/24] fix docs --- docs/generators/kotlin-spring.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/generators/kotlin-spring.md b/docs/generators/kotlin-spring.md index 0c4e836ad7fa..d45963228017 100644 --- a/docs/generators/kotlin-spring.md +++ b/docs/generators/kotlin-spring.md @@ -24,6 +24,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |apiSuffix|suffix for api classes| |Api| |artifactId|Generated artifact id (name of jar).| |openapi-spring| |artifactVersion|Generated artifact's package version.| |1.0.0| +|autoXSpringPaginated|Automatically add x-spring-paginated to operations that have 'page', 'size', and 'sort' query parameters. When enabled, operations with all three parameters will have Pageable support automatically applied. Operations with x-spring-paginated explicitly set to false will not be auto-detected.| |false| |basePackage|base package (invokerPackage) for generated code| |org.openapitools| |beanQualifiers|Whether to add fully-qualifier class names as bean qualifiers in @Component and @RestController annotations. May be used to prevent bean names clash if multiple generated libraries (contexts) added to single project.| |false| |configPackage|configuration package for generated code| |org.openapitools.configuration| @@ -79,6 +80,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |x-maximum-message|Add this property whenever you need to customize the invalidation error message for the maximum value of a variable|FIELD, OPERATION_PARAMETER|null |x-kotlin-implements|Ability to specify interfaces that model must implement|MODEL|empty array |x-kotlin-implements-fields|Specify attributes that are implemented by the interface(s) added via `x-kotlin-implements`|MODEL|empty array +|x-spring-paginated|Add `org.springframework.data.domain.Pageable` to controller method. Can be used to handle `page`, `size` and `sort` query parameters. If these query parameters are also specified in the operation spec, they will be removed from the controller method as their values can be obtained from the `Pageable` object.|OPERATION|false ## IMPORT MAPPING From 14ed53ceafd96d4a0ad219e29058586e4c8c5545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 02:21:11 +0100 Subject: [PATCH 14/24] implement suggestions from CR. Fix declarative interface naming. --- .../languages/KotlinSpringServerCodegen.java | 2 +- .../spring/KotlinSpringServerCodegenTest.java | 12 ++++++------ .../kotlin/petstore-with-x-kotlin-implements.yaml | 14 -------------- .../.openapi-generator/FILES | 6 +++--- .../api/{PetApiClient.kt => PetApi.kt} | 0 .../api/{StoreApiClient.kt => StoreApi.kt} | 0 .../api/{UserApiClient.kt => UserApi.kt} | 0 .../.openapi-generator/FILES | 6 +++--- .../api/{PetApiClient.kt => PetApi.kt} | 0 .../api/{StoreApiClient.kt => StoreApi.kt} | 0 .../api/{UserApiClient.kt => UserApi.kt} | 0 .../.openapi-generator/FILES | 6 +++--- .../api/{PetApiClient.kt => PetApi.kt} | 0 .../api/{StoreApiClient.kt => StoreApi.kt} | 0 .../api/{UserApiClient.kt => UserApi.kt} | 0 .../.openapi-generator/FILES | 6 +++--- .../api/{PetApiClient.kt => PetApi.kt} | 0 .../api/{StoreApiClient.kt => StoreApi.kt} | 0 .../api/{UserApiClient.kt => UserApi.kt} | 0 .../src/main/kotlin/org/openapitools/api/PetApi.kt | 6 ++---- .../kotlin/org/openapitools/api/PetApiDelegate.kt | 6 ++---- .../src/main/kotlin/org/openapitools/api/PetApi.kt | 2 -- 22 files changed, 23 insertions(+), 43 deletions(-) rename samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/{PetApiClient.kt => PetApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/{StoreApiClient.kt => StoreApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/{UserApiClient.kt => UserApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/{PetApiClient.kt => PetApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/{StoreApiClient.kt => StoreApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/{UserApiClient.kt => UserApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/{PetApiClient.kt => PetApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/{StoreApiClient.kt => StoreApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/{UserApiClient.kt => UserApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/{PetApiClient.kt => PetApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/{StoreApiClient.kt => StoreApi.kt} (100%) rename samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/{UserApiClient.kt => UserApi.kt} (100%) 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 5fd5c2cf45c2..02a5bb0a16a9 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 @@ -816,7 +816,7 @@ public void processOpts() { gradleWrapperPackage.replace(".", File.separator), "gradle-wrapper.jar")); } - apiTemplateFiles.put("apiInterface.mustache", "Client.kt"); + apiTemplateFiles.put("apiInterface.mustache", ".kt"); apiTestTemplateFiles.clear(); } 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 8bae29e43d82..7238f01e5bc7 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 @@ -1215,7 +1215,7 @@ public void generateHttpInterfaceReactiveWithReactorResponseEntity() throws Exce generator.opts(input).generate(); - Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApiClient.kt"); + Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApi.kt"); assertFileContains( path, "import reactor.core.publisher.Flux\n" @@ -1287,7 +1287,7 @@ public void generateHttpInterfaceReactiveWithCoroutinesResponseEntity() throws E generator.opts(input).generate(); - Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApiClient.kt"); + Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApi.kt"); assertFileContains( path, " suspend fun getInventory(\n" @@ -1329,7 +1329,7 @@ public void generateHttpInterfaceReactiveWithReactor() throws Exception { generator.opts(input).generate(); - Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApiClient.kt"); + Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApi.kt"); assertFileContains( path, "import reactor.core.publisher.Flux\n" @@ -1377,7 +1377,7 @@ public void generateHttpInterfaceReactiveWithCoroutines() throws Exception { generator.opts(input).generate(); - Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApiClient.kt"); + Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApi.kt"); assertFileContains( path, " suspend fun getInventory(\n" @@ -1418,7 +1418,7 @@ public void generateHttpInterfaceResponseEntity() throws Exception { generator.opts(input).generate(); - Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApiClient.kt"); + Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApi.kt"); assertFileContains( path, " fun getInventory(\n" @@ -1463,7 +1463,7 @@ public void generateHttpInterface() throws Exception { generator.opts(input).generate(); - Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApiClient.kt"); + Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/StoreApi.kt"); // Note: We cannot use property placeholders as HttpServiceProxyFactory does not resolve them by default. assertFileContains( path, diff --git a/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml b/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml index 8e6b8b24e9e7..e3a8f414e755 100644 --- a/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml @@ -797,13 +797,6 @@ paths: description: Tests x-spring-paginated with no query params except pagination operationId: listPetsByIdPaginated parameters: - - name: petId - in: path - description: Pet ID - required: true - schema: - type: integer - format: int64 - name: X-Request-ID in: header description: Request ID for tracing @@ -842,13 +835,6 @@ paths: description: Comprehensive test with all parameter types operationId: listPetsMixedParams parameters: - - name: categoryId - in: path - description: Category ID - required: true - schema: - type: integer - format: int64 - name: Authorization in: header description: Authorization header diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/.openapi-generator/FILES b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/.openapi-generator/FILES index 18f6d4999914..6d78af78d508 100644 --- a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/.openapi-generator/FILES +++ b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/.openapi-generator/FILES @@ -6,9 +6,9 @@ gradlew gradlew.bat pom.xml settings.gradle -src/main/kotlin/org/openapitools/api/PetApiClient.kt -src/main/kotlin/org/openapitools/api/StoreApiClient.kt -src/main/kotlin/org/openapitools/api/UserApiClient.kt +src/main/kotlin/org/openapitools/api/PetApi.kt +src/main/kotlin/org/openapitools/api/StoreApi.kt +src/main/kotlin/org/openapitools/api/UserApi.kt src/main/kotlin/org/openapitools/model/Category.kt src/main/kotlin/org/openapitools/model/ModelApiResponse.kt src/main/kotlin/org/openapitools/model/Order.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/PetApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/PetApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/PetApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/PetApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/StoreApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/StoreApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/StoreApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/StoreApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/UserApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/UserApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/UserApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-reactive-coroutines/src/main/kotlin/org/openapitools/api/UserApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/.openapi-generator/FILES b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/.openapi-generator/FILES index 18f6d4999914..6d78af78d508 100644 --- a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/.openapi-generator/FILES +++ b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/.openapi-generator/FILES @@ -6,9 +6,9 @@ gradlew gradlew.bat pom.xml settings.gradle -src/main/kotlin/org/openapitools/api/PetApiClient.kt -src/main/kotlin/org/openapitools/api/StoreApiClient.kt -src/main/kotlin/org/openapitools/api/UserApiClient.kt +src/main/kotlin/org/openapitools/api/PetApi.kt +src/main/kotlin/org/openapitools/api/StoreApi.kt +src/main/kotlin/org/openapitools/api/UserApi.kt src/main/kotlin/org/openapitools/model/Category.kt src/main/kotlin/org/openapitools/model/ModelApiResponse.kt src/main/kotlin/org/openapitools/model/Order.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/PetApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/PetApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/PetApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/PetApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/StoreApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/StoreApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/StoreApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/StoreApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/UserApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/UserApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/UserApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-reactive-reactor-wrapped/src/main/kotlin/org/openapitools/api/UserApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/.openapi-generator/FILES b/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/.openapi-generator/FILES index 18f6d4999914..6d78af78d508 100644 --- a/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/.openapi-generator/FILES +++ b/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/.openapi-generator/FILES @@ -6,9 +6,9 @@ gradlew gradlew.bat pom.xml settings.gradle -src/main/kotlin/org/openapitools/api/PetApiClient.kt -src/main/kotlin/org/openapitools/api/StoreApiClient.kt -src/main/kotlin/org/openapitools/api/UserApiClient.kt +src/main/kotlin/org/openapitools/api/PetApi.kt +src/main/kotlin/org/openapitools/api/StoreApi.kt +src/main/kotlin/org/openapitools/api/UserApi.kt src/main/kotlin/org/openapitools/model/Category.kt src/main/kotlin/org/openapitools/model/ModelApiResponse.kt src/main/kotlin/org/openapitools/model/Order.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/PetApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/PetApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/PetApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/PetApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/StoreApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/StoreApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/StoreApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/StoreApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/UserApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/UserApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/UserApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface-wrapped/src/main/kotlin/org/openapitools/api/UserApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface/.openapi-generator/FILES b/samples/server/petstore/kotlin-spring-declarative-interface/.openapi-generator/FILES index 18f6d4999914..6d78af78d508 100644 --- a/samples/server/petstore/kotlin-spring-declarative-interface/.openapi-generator/FILES +++ b/samples/server/petstore/kotlin-spring-declarative-interface/.openapi-generator/FILES @@ -6,9 +6,9 @@ gradlew gradlew.bat pom.xml settings.gradle -src/main/kotlin/org/openapitools/api/PetApiClient.kt -src/main/kotlin/org/openapitools/api/StoreApiClient.kt -src/main/kotlin/org/openapitools/api/UserApiClient.kt +src/main/kotlin/org/openapitools/api/PetApi.kt +src/main/kotlin/org/openapitools/api/StoreApi.kt +src/main/kotlin/org/openapitools/api/UserApi.kt src/main/kotlin/org/openapitools/model/Category.kt src/main/kotlin/org/openapitools/model/ModelApiResponse.kt src/main/kotlin/org/openapitools/model/Order.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/PetApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/PetApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/PetApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/PetApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/StoreApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/StoreApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/StoreApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/StoreApi.kt diff --git a/samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/UserApiClient.kt b/samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/UserApi.kt similarity index 100% rename from samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/UserApiClient.kt rename to samples/server/petstore/kotlin-spring-declarative-interface/src/main/kotlin/org/openapitools/api/UserApi.kt diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt index 2d904f839901..9a0c20bb669f 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -205,12 +205,11 @@ interface PetApi { produces = ["application/json"] ) fun listPetsByIdPaginated( - @ApiParam(value = "Pet ID", required = true) @PathVariable("petId") petId: kotlin.Long, @ApiParam(value = "Request ID for tracing") @RequestHeader(value = "X-Request-ID", required = false) xRequestID: kotlin.String?, @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, @ApiParam(hidden = true) pageable: Pageable ): ResponseEntity> { - return getDelegate().listPetsByIdPaginated(petId, xRequestID, exchange, pageable) + return getDelegate().listPetsByIdPaginated(xRequestID, exchange, pageable) } @@ -257,7 +256,6 @@ interface PetApi { produces = ["application/json"] ) fun listPetsMixedParams( - @ApiParam(value = "Category ID", required = true) @PathVariable("categoryId") categoryId: kotlin.Long, @ApiParam(value = "Authorization header") @RequestHeader(value = "Authorization", required = false) authorization: kotlin.String?, @ApiParam(value = "Tenant ID") @RequestHeader(value = "X-Tenant-ID", required = false) xTenantID: kotlin.String?, @ApiParam(value = "Status filter") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, @@ -265,7 +263,7 @@ interface PetApi { @ApiParam(hidden = true) exchange: org.springframework.web.server.ServerWebExchange, @ApiParam(hidden = true) pageable: Pageable ): ResponseEntity> { - return getDelegate().listPetsMixedParams(categoryId, authorization, xTenantID, status, includeInactive, exchange, pageable) + return getDelegate().listPetsMixedParams(authorization, xTenantID, status, includeInactive, exchange, pageable) } diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt index 7513f4fadf58..ff85edeb0007 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/src/main/kotlin/org/openapitools/api/PetApiDelegate.kt @@ -66,8 +66,7 @@ interface PetApiDelegate { /** * @see PetApi#listPetsByIdPaginated */ - fun listPetsByIdPaginated(petId: kotlin.Long, - xRequestID: kotlin.String?, + fun listPetsByIdPaginated(xRequestID: kotlin.String?, exchange: org.springframework.web.server.ServerWebExchange, pageable: Pageable): ResponseEntity> @@ -84,8 +83,7 @@ interface PetApiDelegate { /** * @see PetApi#listPetsMixedParams */ - fun listPetsMixedParams(categoryId: kotlin.Long, - authorization: kotlin.String?, + fun listPetsMixedParams(authorization: kotlin.String?, xTenantID: kotlin.String?, status: kotlin.String?, includeInactive: kotlin.Boolean?, diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt index d5df7f08f2c9..828ae7b810f9 100644 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt +++ b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/src/main/kotlin/org/openapitools/api/PetApi.kt @@ -190,7 +190,6 @@ interface PetApi { produces = ["application/json"] ) fun listPetsByIdPaginated( - @ApiParam(value = "Pet ID", required = true) @PathVariable("petId") petId: kotlin.Long, @ApiParam(value = "Request ID for tracing") @RequestHeader(value = "X-Request-ID", required = false) xRequestID: kotlin.String?, @ApiParam(hidden = true) request: javax.servlet.http.HttpServletRequest, @ApiParam(hidden = true) pageable: Pageable @@ -238,7 +237,6 @@ interface PetApi { produces = ["application/json"] ) fun listPetsMixedParams( - @ApiParam(value = "Category ID", required = true) @PathVariable("categoryId") categoryId: kotlin.Long, @ApiParam(value = "Authorization header") @RequestHeader(value = "Authorization", required = false) authorization: kotlin.String?, @ApiParam(value = "Tenant ID") @RequestHeader(value = "X-Tenant-ID", required = false) xTenantID: kotlin.String?, @ApiParam(value = "Status filter") @Valid @RequestParam(value = "status", required = false) status: kotlin.String?, From c92887f0ba0126758a307cdc44bc9c0b3823181e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 10:07:21 +0100 Subject: [PATCH 15/24] move import around --- .../libraries/spring-boot/buildGradle-sb3-Kts.mustache | 4 ++-- .../libraries/spring-boot/buildGradleKts.mustache | 4 ++-- .../server/petstore/kotlin-spring-default/build.gradle.kts | 2 +- .../kotlin-springboot-3-no-response-entity/build.gradle.kts | 2 +- samples/server/petstore/kotlin-springboot-3/build.gradle.kts | 2 +- .../kotlin-springboot-additionalproperties/build.gradle.kts | 2 +- .../kotlin-springboot-bigdecimal-default/build.gradle.kts | 2 +- .../kotlin-springboot-delegate-nodefaults/build.gradle.kts | 2 +- .../petstore/kotlin-springboot-delegate/build.gradle.kts | 2 +- .../build.gradle.kts | 2 +- .../petstore/kotlin-springboot-integer-enum/build.gradle.kts | 2 +- .../petstore/kotlin-springboot-modelMutable/build.gradle.kts | 2 +- .../build.gradle.kts | 2 +- .../build.gradle.kts | 2 +- .../kotlin-springboot-no-response-entity/build.gradle.kts | 2 +- .../kotlin-springboot-reactive-without-flow/build.gradle.kts | 2 +- .../petstore/kotlin-springboot-reactive/build.gradle.kts | 2 +- .../kotlin-springboot-request-cookie/build.gradle.kts | 2 +- .../kotlin-springboot-source-swagger1/build.gradle.kts | 2 +- .../kotlin-springboot-source-swagger2/build.gradle.kts | 2 +- .../petstore/kotlin-springboot-springfox/build.gradle.kts | 2 +- .../kotlin-springboot-x-kotlin-implements/build.gradle.kts | 2 +- samples/server/petstore/kotlin-springboot/build.gradle.kts | 2 +- 23 files changed, 25 insertions(+), 25 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache index 555c9c45757b..5e33e8653404 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache @@ -31,8 +31,7 @@ plugins { dependencies { {{#reactive}} val kotlinxCoroutinesVersion = "1.6.1" {{/reactive}} implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons"){{^reactive}} + implementation("org.jetbrains.kotlin:kotlin-reflect"){{^reactive}} implementation("org.springframework.boot:spring-boot-starter-web"){{/reactive}}{{#reactive}} implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") @@ -50,6 +49,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") {{#useBeanValidation}} implementation("jakarta.validation:jakarta.validation-api"){{/useBeanValidation}} implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache index 100976c80644..7b72c8568112 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache @@ -38,8 +38,7 @@ plugins { dependencies { {{#reactive}} val kotlinxCoroutinesVersion = "1.6.1" {{/reactive}} implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons"){{^reactive}} + implementation("org.jetbrains.kotlin:kotlin-reflect"){{^reactive}} implementation("org.springframework.boot:spring-boot-starter-web"){{/reactive}}{{#reactive}} implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") @@ -57,6 +56,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") {{#useBeanValidation}} implementation("javax.validation:validation-api"){{/useBeanValidation}} implementation("javax.annotation:javax.annotation-api:1.3.2") diff --git a/samples/server/petstore/kotlin-spring-default/build.gradle.kts b/samples/server/petstore/kotlin-spring-default/build.gradle.kts index 9153b932e804..319a704f5842 100644 --- a/samples/server/petstore/kotlin-spring-default/build.gradle.kts +++ b/samples/server/petstore/kotlin-spring-default/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") @@ -41,6 +40,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts b/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts index 19efbcc9ca07..db73c5e21693 100644 --- a/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts @@ -25,7 +25,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -33,6 +32,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("jakarta.validation:jakarta.validation-api") implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/samples/server/petstore/kotlin-springboot-3/build.gradle.kts b/samples/server/petstore/kotlin-springboot-3/build.gradle.kts index 19efbcc9ca07..db73c5e21693 100644 --- a/samples/server/petstore/kotlin-springboot-3/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-3/build.gradle.kts @@ -25,7 +25,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -33,6 +32,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("jakarta.validation:jakarta.validation-api") implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts b/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts index 19efbcc9ca07..db73c5e21693 100644 --- a/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts @@ -25,7 +25,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -33,6 +32,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("jakarta.validation:jakarta.validation-api") implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts b/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts index 9153b932e804..319a704f5842 100644 --- a/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-bigdecimal-default/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") @@ -41,6 +40,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts b/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts index 33c3634ee8dc..6122df330e69 100644 --- a/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts @@ -25,7 +25,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("io.swagger.core.v3:swagger-annotations:2.2.0") @@ -34,6 +33,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("jakarta.validation:jakarta.validation-api") implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts b/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts index 9153b932e804..319a704f5842 100644 --- a/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-delegate/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") @@ -41,6 +40,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts index 26783d8398f4..3fa8025c39dd 100644 --- a/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-include-http-request-context-delegate/build.gradle.kts @@ -33,7 +33,6 @@ dependencies { val kotlinxCoroutinesVersion = "1.6.1" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion") @@ -44,6 +43,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts b/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts index f5c38c84f3d2..559b1f327bec 100644 --- a/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts @@ -29,7 +29,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -37,6 +36,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("jakarta.validation:jakarta.validation-api") implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts b/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts index 9153b932e804..319a704f5842 100644 --- a/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-modelMutable/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") @@ -41,6 +40,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts b/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts index 9153b932e804..319a704f5842 100644 --- a/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-multipart-request-model/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-ui:1.6.8") @@ -41,6 +40,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts b/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts index 63f5d8f6fe81..b3086b53f094 100644 --- a/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-no-response-entity-delegate/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -40,6 +39,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts b/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts index 63f5d8f6fe81..b3086b53f094 100644 --- a/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-no-response-entity/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -40,6 +39,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts b/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts index 0318dbf63035..f8d51547a12e 100644 --- a/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-reactive-without-flow/build.gradle.kts @@ -33,7 +33,6 @@ dependencies { val kotlinxCoroutinesVersion = "1.6.1" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion") @@ -44,6 +43,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts b/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts index 0318dbf63035..f8d51547a12e 100644 --- a/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-reactive/build.gradle.kts @@ -33,7 +33,6 @@ dependencies { val kotlinxCoroutinesVersion = "1.6.1" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion") @@ -44,6 +43,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts b/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts index f2ae840a132b..fa644c9b144c 100644 --- a/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts @@ -29,7 +29,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0") @@ -38,6 +37,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("jakarta.validation:jakarta.validation-api") implementation("jakarta.annotation:jakarta.annotation-api:2.1.0") diff --git a/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts b/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts index 28bae7b0e3d2..cd5e76efe1bd 100644 --- a/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-source-swagger1/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.webjars:swagger-ui:4.10.3") implementation("org.webjars:webjars-locator-core") @@ -43,6 +42,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts b/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts index 57d707185de1..bab28e4573e9 100644 --- a/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-source-swagger2/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.webjars:swagger-ui:4.10.3") implementation("org.webjars:webjars-locator-core") @@ -43,6 +42,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts b/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts index 44e3c1977252..cad1242edc51 100644 --- a/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-springfox/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("io.springfox:springfox-swagger2:2.9.2") implementation("org.webjars:swagger-ui:4.10.3") @@ -43,6 +42,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts index 8fa3f976d1a4..39df365c5d0b 100644 --- a/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot-x-kotlin-implements/build.gradle.kts @@ -36,7 +36,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("io.swagger:swagger-annotations:1.6.6") @@ -45,6 +44,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/samples/server/petstore/kotlin-springboot/build.gradle.kts b/samples/server/petstore/kotlin-springboot/build.gradle.kts index 63f5d8f6fe81..b3086b53f094 100644 --- a/samples/server/petstore/kotlin-springboot/build.gradle.kts +++ b/samples/server/petstore/kotlin-springboot/build.gradle.kts @@ -32,7 +32,6 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.springframework.data:spring-data-commons") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.google.code.findbugs:jsr305:3.0.2") @@ -40,6 +39,7 @@ dependencies { implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.data:spring-data-commons") implementation("javax.validation:validation-api") implementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") From 4aadf0f17c6f42f6240d50f08f23eabcc357bf6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 11:04:47 +0100 Subject: [PATCH 16/24] add x-operation-extra-annotation --- .../languages/KotlinSpringServerCodegen.java | 15 ++++--- .../main/resources/kotlin-spring/api.mustache | 3 ++ .../kotlin-spring/apiInterface.mustache | 3 ++ .../spring/KotlinSpringServerCodegenTest.java | 45 ++++++++++++++++++- 4 files changed, 58 insertions(+), 8 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 02a5bb0a16a9..63326c2ccf68 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 @@ -483,6 +483,7 @@ public void processOpts() { // Spring-specific import mappings for x-spring-paginated support importMapping.put("ApiIgnore", "springfox.documentation.annotations.ApiIgnore"); importMapping.put("ParameterObject", "org.springdoc.api.annotations.ParameterObject"); + importMapping.put("PageableAsQueryParam", "org.springdoc.core.converters.models.PageableAsQueryParam"); if (useSpringBoot3) { importMapping.put("ParameterObject", "org.springdoc.core.annotations.ParameterObject"); } @@ -924,16 +925,17 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers); + // Check if operation has all three pagination query parameters (case-sensitive) + boolean hasParamsForPageable = codegenOperation.queryParams.stream() + .map(p -> p.baseName) + .collect(Collectors.toSet()) + .containsAll(defaultPageableQueryParams); // Auto-detect pagination parameters and add x-spring-paginated if autoXSpringPaginated is enabled // Only for spring-boot library, respect manual x-spring-paginated: false setting if (SPRING_BOOT.equals(library) && autoXSpringPaginated) { // Check if x-spring-paginated is not explicitly set to false if (operation.getExtensions() == null || !Boolean.FALSE.equals(operation.getExtensions().get("x-spring-paginated"))) { - // Check if operation has all three pagination query parameters (case-sensitive) - boolean hasParamsForPageable = codegenOperation.queryParams.stream() - .map(p -> p.baseName) - .collect(Collectors.toSet()) - .containsAll(defaultPageableQueryParams); + if (hasParamsForPageable) { // Automatically add x-spring-paginated to the operation @@ -962,7 +964,8 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation codegenOperation.imports.add("ApiIgnore"); } if (DocumentationProvider.SPRINGDOC.equals(getDocumentationProvider())) { - codegenOperation.imports.add("ParameterObject"); + codegenOperation.imports.add("PageableAsQueryParam"); + codegenOperation.vendorExtensions.put("x-operation-extra-annotation", "@PageableAsQueryParam"); } // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache index 3b9e4fe25805..284cb4aecedb 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache @@ -84,6 +84,9 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v authorizations = [{{#authMethods}}Authorization(value = "{{name}}"{{#isOAuth}}, scopes = [{{#scopes}}AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{^-last}}, {{/-last}}{{/scopes}}]{{/isOAuth}}){{^-last}}, {{/-last}}{{/authMethods}}]{{/hasAuthMethods}}) @ApiResponses( value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{.}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}){{^-last}},{{/-last}}{{/responses}}]){{/swagger1AnnotationLibrary}} + {{#vendorExtensions.x-operation-extra-annotation}} + {{{.}}} + {{/vendorExtensions.x-operation-extra-annotation}} @RequestMapping( method = [RequestMethod.{{httpMethod}}], // "{{#lambdaEscapeInNormalString}}{{{path}}}{{/lambdaEscapeInNormalString}}" diff --git a/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache b/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache index 0df5348fbeef..3b130aadbc58 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache @@ -99,6 +99,9 @@ interface {{classname}} { @ApiResponses( value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{.}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}){{^-last}}, {{/-last}}{{/responses}}] ){{/swagger1AnnotationLibrary}} + {{#vendorExtensions.x-operation-extra-annotation}} + {{{.}}} + {{/vendorExtensions.x-operation-extra-annotation}} @RequestMapping( method = [RequestMethod.{{httpMethod}}], // "{{#lambdaEscapeInNormalString}}{{{path}}}{{/lambdaEscapeInNormalString}}" 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 7238f01e5bc7..fb8c9aa44552 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 @@ -3678,7 +3678,6 @@ public void springPaginatedWithSpringDoc() throws Exception { File petApi = files.get("PetApi.kt"); assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); - assertFileContains(petApi.toPath(), "import org.springdoc.api.annotations.ParameterObject"); assertFileContains(petApi.toPath(), "pageable: Pageable"); assertFileContains(petApi.toPath(), "@Parameter(hidden = true) pageable: Pageable"); } @@ -3696,7 +3695,6 @@ public void springPaginatedWithSpringDocAndSpringBoot3() throws Exception { File petApi = files.get("PetApi.kt"); assertFileContains(petApi.toPath(), "import org.springframework.data.domain.Pageable"); - assertFileContains(petApi.toPath(), "import org.springdoc.core.annotations.ParameterObject"); assertFileContains(petApi.toPath(), "pageable: Pageable"); } @@ -3862,6 +3860,49 @@ public void springPaginatedWithSwagger1AnnotationLibrary() throws Exception { assertFileContains(petApi.toPath(), "@ApiParam(hidden = true) pageable: Pageable"); } + @Test + public void springPaginatedWithSpringDocUsesPageableAsQueryParam() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Verify @PageableAsQueryParam annotation is present at method level + assertFileContains(petApi.toPath(), "import org.springdoc.core.converters.models.PageableAsQueryParam"); + assertFileContains(petApi.toPath(), "@PageableAsQueryParam"); + + // Verify Pageable parameter has @Parameter(hidden = true) + assertFileContains(petApi.toPath(), "@Parameter(hidden = true) pageable: Pageable"); + + // Verify the annotation appears before @RequestMapping for findPetsByStatus + int findPetsByStatusStart = content.indexOf("fun findPetsByStatus("); + Assert.assertTrue(findPetsByStatusStart > 0, "findPetsByStatus method should exist"); + + String methodBlock = content.substring(Math.max(0, findPetsByStatusStart - 1000), findPetsByStatusStart); + int pageableAsQueryParamPos = methodBlock.lastIndexOf("@PageableAsQueryParam"); + int requestMappingPos = methodBlock.lastIndexOf("@RequestMapping"); + + Assert.assertTrue(pageableAsQueryParamPos > 0, "@PageableAsQueryParam should be present before method"); + Assert.assertTrue(requestMappingPos > pageableAsQueryParamPos, + "@PageableAsQueryParam should appear before @RequestMapping"); + + // Verify page, size, sort parameters are NOT in the method signature + String methodSignature = content.substring(findPetsByStatusStart, + content.indexOf("): ResponseEntity", findPetsByStatusStart)); + Assert.assertFalse(methodSignature.contains("page:"), + "page parameter should be removed from method signature"); + Assert.assertFalse(methodSignature.contains("size:") && methodSignature.contains("@RequestParam"), + "size query parameter should be removed from method signature"); + Assert.assertFalse(methodSignature.contains("sort:"), + "sort parameter should be removed from method signature"); + } + @Test public void springPaginatedNoParamsNoContext() throws Exception { Map additionalProperties = new HashMap<>(); From 69858d48891d38cb41c8dd3946b71bc2670282e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 11:24:31 +0100 Subject: [PATCH 17/24] make sure the PageableAsQueryParam does not remove already present x-operation-extra-annotation content --- .../languages/KotlinSpringServerCodegen.java | 9 +++- .../spring/KotlinSpringServerCodegenTest.java | 43 +++++++++++++++++++ .../spring/petstore-with-spring-pageable.yaml | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) 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 63326c2ccf68..ee2d9fe786f6 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 @@ -965,7 +965,14 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation } if (DocumentationProvider.SPRINGDOC.equals(getDocumentationProvider())) { codegenOperation.imports.add("PageableAsQueryParam"); - codegenOperation.vendorExtensions.put("x-operation-extra-annotation", "@PageableAsQueryParam"); + // Prepend @PageableAsQueryParam to existing x-operation-extra-annotation if present + Object existingAnnotation = codegenOperation.vendorExtensions.get("x-operation-extra-annotation"); + if (existingAnnotation != null && !existingAnnotation.toString().isEmpty()) { + codegenOperation.vendorExtensions.put("x-operation-extra-annotation", + "@PageableAsQueryParam\n " + existingAnnotation); + } else { + codegenOperation.vendorExtensions.put("x-operation-extra-annotation", "@PageableAsQueryParam"); + } } // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used 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 fb8c9aa44552..8408b6f95987 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 @@ -3918,6 +3918,49 @@ public void springPaginatedNoParamsNoContext() throws Exception { assertFileContains(petApi.toPath(), "fun listAllPets(@Parameter(hidden = true) pageable: Pageable)"); } + @Test + public void springPaginatedWithSpringDocPrependsToExistingAnnotation() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Verify that both annotations are imported + assertFileContains(petApi.toPath(), "import org.springdoc.core.converters.models.PageableAsQueryParam"); + assertFileContains(petApi.toPath(), "import org.springframework.validation.annotation.Validated"); + + // Find the listAllPets method + int listAllPetsStart = content.indexOf("fun listAllPets("); + Assert.assertTrue(listAllPetsStart > 0, "listAllPets method should exist"); + + // Check the annotations appear before the method in the correct order + String methodBlock = content.substring(Math.max(0, listAllPetsStart - 1000), listAllPetsStart); + + int pageableAsQueryParamPos = methodBlock.lastIndexOf("@PageableAsQueryParam"); + int validatedPos = methodBlock.lastIndexOf("@org.springframework.validation.annotation.Validated"); + int requestMappingPos = methodBlock.lastIndexOf("@RequestMapping"); + + Assert.assertTrue(pageableAsQueryParamPos > 0, "@PageableAsQueryParam should be present before listAllPets method"); + Assert.assertTrue(validatedPos > 0, "@Validated should be present before listAllPets method"); + + // Verify @PageableAsQueryParam comes before @Validated (prepended) + Assert.assertTrue(pageableAsQueryParamPos < validatedPos, + "@PageableAsQueryParam should be prepended (appear before) existing @Validated annotation"); + + // Verify both annotations come before @RequestMapping + Assert.assertTrue(validatedPos < requestMappingPos, + "Both annotations should appear before @RequestMapping"); + + // Verify the Pageable parameter still has @Parameter(hidden = true) + assertFileContains(petApi.toPath(), "@Parameter(hidden = true) pageable: Pageable"); + } + @Test public void springPaginatedMixedOperations() throws Exception { Map additionalProperties = new HashMap<>(); diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml index 792521466546..8490ab8efb6e 100644 --- a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml @@ -243,6 +243,7 @@ paths: - write:pets - read:pets x-spring-paginated: true + x-operation-extra-annotation: "@org.springframework.validation.annotation.Validated" # test that the annotation is preserved when x-spring-paginated:true is used and is prepended with the @PageableAsQueryParam for springdoc /pet/{petId}: get: tags: From fc10db41c86a75b586bc3bfb57be04a6c254426d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 11:56:54 +0100 Subject: [PATCH 18/24] support also list format --- .../languages/KotlinSpringServerCodegen.java | 19 +++++--- .../spring/KotlinSpringServerCodegenTest.java | 48 +++++++++++++++++++ .../spring/petstore-with-spring-pageable.yaml | 3 ++ .../java/org/openapitools/api/PetApi.java | 1 + 4 files changed, 65 insertions(+), 6 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 ee2d9fe786f6..55abde3ad6c5 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 @@ -966,13 +966,19 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation if (DocumentationProvider.SPRINGDOC.equals(getDocumentationProvider())) { codegenOperation.imports.add("PageableAsQueryParam"); // Prepend @PageableAsQueryParam to existing x-operation-extra-annotation if present + // Use getObjectAsStringList to properly handle both list and string formats: + // - YAML list: ['@Ann1', '@Ann2'] -> List of annotations + // - Single string: '@Ann1 @Ann2' -> Single-element list + // - Nothing/null -> Empty list Object existingAnnotation = codegenOperation.vendorExtensions.get("x-operation-extra-annotation"); - if (existingAnnotation != null && !existingAnnotation.toString().isEmpty()) { - codegenOperation.vendorExtensions.put("x-operation-extra-annotation", - "@PageableAsQueryParam\n " + existingAnnotation); - } else { - codegenOperation.vendorExtensions.put("x-operation-extra-annotation", "@PageableAsQueryParam"); - } + List annotations = DefaultCodegen.getObjectAsStringList(existingAnnotation); + + // Prepend @PageableAsQueryParam to the beginning of the list + List updatedAnnotations = new ArrayList<>(); + updatedAnnotations.add("@PageableAsQueryParam"); + updatedAnnotations.addAll(annotations); + + codegenOperation.vendorExtensions.put("x-operation-extra-annotation", updatedAnnotations); } // #8315 Remove matching Spring Data Web default query params if 'x-spring-paginated' with Pageable is used @@ -1228,6 +1234,7 @@ public List getSupportedVendorExtensions() { extensions.add(VendorExtension.X_CONTENT_TYPE); extensions.add(VendorExtension.X_DISCRIMINATOR_VALUE); extensions.add(VendorExtension.X_FIELD_EXTRA_ANNOTATION); + extensions.add(VendorExtension.X_OPERATION_EXTRA_ANNOTATION); extensions.add(VendorExtension.X_PATTERN_MESSAGE); extensions.add(VendorExtension.X_SIZE_MESSAGE); extensions.add(VendorExtension.X_MINIMUM_MESSAGE); 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 8408b6f95987..353c5141c910 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 @@ -3961,6 +3961,54 @@ public void springPaginatedWithSpringDocPrependsToExistingAnnotation() throws Ex assertFileContains(petApi.toPath(), "@Parameter(hidden = true) pageable: Pageable"); } + @Test + public void springPaginatedWithSpringDocPrependsToExistingAnnotationArray() throws Exception { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(USE_TAGS, "true"); + additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc"); + additionalProperties.put(INTERFACE_ONLY, "true"); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true"); + + Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + + File petApi = files.get("PetApi.kt"); + String content = Files.readString(petApi.toPath()); + + // Verify that PageableAsQueryParam is imported + assertFileContains(petApi.toPath(), "import org.springdoc.core.converters.models.PageableAsQueryParam"); + + // Find the findPetsByStatus method + int findPetsByStatusStart = content.indexOf("fun findPetsByStatus("); + Assert.assertTrue(findPetsByStatusStart > 0, "findPetsByStatus method should exist"); + + // Check the annotations appear before the method in the correct order + String methodBlock = content.substring(Math.max(0, findPetsByStatusStart - 1500), findPetsByStatusStart); + + int pageableAsQueryParamPos = methodBlock.lastIndexOf("@PageableAsQueryParam"); + int validatedPos = methodBlock.lastIndexOf("@org.springframework.validation.annotation.Validated"); + int preAuthorizePos = methodBlock.lastIndexOf("@org.springframework.security.access.prepost.PreAuthorize"); + int requestMappingPos = methodBlock.lastIndexOf("@RequestMapping"); + + Assert.assertTrue(pageableAsQueryParamPos > 0, "@PageableAsQueryParam should be present before findPetsByStatus method"); + Assert.assertTrue(validatedPos > 0, "@Validated should be present before findPetsByStatus method"); + Assert.assertTrue(preAuthorizePos > 0, "@PreAuthorize should be present before findPetsByStatus method"); + + // Verify @PageableAsQueryParam comes first (prepended to the array) + Assert.assertTrue(pageableAsQueryParamPos < validatedPos, + "@PageableAsQueryParam should be prepended (appear before) @Validated annotation"); + + // Verify the original array order is preserved after @PageableAsQueryParam + Assert.assertTrue(validatedPos < preAuthorizePos, + "@Validated should appear before @PreAuthorize (original array order preserved)"); + + // Verify all annotations come before @RequestMapping + Assert.assertTrue(preAuthorizePos < requestMappingPos, + "All annotations should appear before @RequestMapping"); + + // Verify the Pageable parameter still has @Parameter(hidden = true) + assertFileContains(petApi.toPath(), "@Parameter(hidden = true) pageable: Pageable"); + } + @Test public void springPaginatedMixedOperations() throws Exception { Map additionalProperties = new HashMap<>(); diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml index 8490ab8efb6e..5b37c7e65a73 100644 --- a/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml @@ -117,6 +117,9 @@ paths: - write:pets - read:pets x-spring-paginated: true + x-operation-extra-annotation: + - "@org.springframework.validation.annotation.Validated" + - "@org.springframework.security.access.prepost.PreAuthorize(\"hasRole('ADMIN')\")" /pet/findByTags: get: tags: diff --git a/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java b/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java index acadc4d62506..dbb3e3834cf3 100644 --- a/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java @@ -239,6 +239,7 @@ ResponseEntity getPetById( value = PetApi.PATH_LIST_ALL_PETS, produces = { "application/json", "application/xml" } ) + @org.springframework.validation.annotation.Validated ResponseEntity> listAllPets( @ParameterObject final Pageable pageable ); From ccb7fd29fd421da4d6923813bf20cedd195d703f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 12:05:45 +0100 Subject: [PATCH 19/24] regenerate samples and docs --- .../src/main/java/org/openapitools/api/PetApi.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java b/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java index dbb3e3834cf3..0b3df238b4e5 100644 --- a/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/PetApi.java @@ -126,6 +126,8 @@ ResponseEntity deletePet( value = PetApi.PATH_FIND_PETS_BY_STATUS, produces = { "application/json", "application/xml" } ) + @org.springframework.validation.annotation.Validated + @org.springframework.security.access.prepost.PreAuthorize("hasRole('ADMIN')") ResponseEntity> findPetsByStatus( @NotNull @Parameter(name = "status", description = "Status values that need to be considered for filter", required = true, in = ParameterIn.QUERY) @Valid @RequestParam(value = "status", required = true) List status, @ParameterObject final Pageable pageable From 25cb530244afce27de368657f28979ee73058f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 12:34:49 +0100 Subject: [PATCH 20/24] regenerate samples and docs --- docs/generators/kotlin-spring.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/generators/kotlin-spring.md b/docs/generators/kotlin-spring.md index d45963228017..e03dfd102929 100644 --- a/docs/generators/kotlin-spring.md +++ b/docs/generators/kotlin-spring.md @@ -74,6 +74,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |x-content-type|Specify custom value for 'Content-Type' header for operation|OPERATION|null |x-discriminator-value|Used with model inheritance to specify value for discriminator that identifies current model|MODEL| |x-field-extra-annotation|List of custom annotations to be added to property|FIELD, OPERATION_PARAMETER|null +|x-operation-extra-annotation|List of custom annotations to be added to operation|OPERATION|null |x-pattern-message|Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable|FIELD, OPERATION_PARAMETER|null |x-size-message|Add this property whenever you need to customize the invalidation error message for the size or length of a variable|FIELD, OPERATION_PARAMETER|null |x-minimum-message|Add this property whenever you need to customize the invalidation error message for the minimum value of a variable|FIELD, OPERATION_PARAMETER|null From b9b339220d6ff61d7afc5441c4c8518bf30274cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 12:42:38 +0100 Subject: [PATCH 21/24] force tests rerun --- .../codegen/kotlin/spring/KotlinSpringServerCodegenTest.java | 1 + 1 file changed, 1 insertion(+) 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 353c5141c910..b7bdcbf79d65 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 @@ -3971,6 +3971,7 @@ public void springPaginatedWithSpringDocPrependsToExistingAnnotationArray() thro Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); + File petApi = files.get("PetApi.kt"); String content = Files.readString(petApi.toPath()); From b582f1653e95d8f655f7634d18dd634f6b1fc703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 13:08:56 +0100 Subject: [PATCH 22/24] remove files --- .../kotlin/org/openapitools/server/Main.kt | 16 ------- .../org/openapitools/server/models/Cat.kt | 42 ------------------- .../org/openapitools/server/models/Dog.kt | 29 ------------- .../org/openapitools/server/models/Pet.kt | 32 -------------- 4 files changed, 119 deletions(-) delete mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt delete mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt delete mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt delete mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt deleted file mode 100644 index dba7f137ec60..000000000000 --- a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.openapitools.server - -import io.javalin.Javalin -import io.javalin.apibuilder.ApiBuilder.* - - -fun main() { - - val app = Javalin - .create { config -> - config.router.apiBuilder { - } - } - - app.start() -} diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt deleted file mode 100644 index 99ab4e0f3f50..000000000000 --- a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Basic polymorphism example with discriminator - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. -*/ -package org.openapitools.server.models - - -/** - * A pet cat - * @param huntingSkill The measured skill for hunting - * @param petType - */ -data class Cat( - /* The measured skill for hunting */ - - @field:com.fasterxml.jackson.annotation.JsonProperty("huntingSkill") - val huntingSkill: Cat.HuntingSkill, - - @field:com.fasterxml.jackson.annotation.JsonProperty("petType") - override val petType: kotlin.String = "cat", - -) : Pet(petType = petType) -{ - /** - * The measured skill for hunting - * Values: clueless,lazy,adventurous,aggressive - */ - enum class HuntingSkill(val value: kotlin.String){ - clueless("clueless"), - lazy("lazy"), - adventurous("adventurous"), - aggressive("aggressive"); - } -} - diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt deleted file mode 100644 index 9f3cbe860d93..000000000000 --- a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Basic polymorphism example with discriminator - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. -*/ -package org.openapitools.server.models - - -/** - * A pet dog - * @param petType - * @param packSize the size of the pack the dog is from - */ -data class Dog( - - @field:com.fasterxml.jackson.annotation.JsonProperty("petType") - override val petType: kotlin.String = "dog", - /* the size of the pack the dog is from */ - - @field:com.fasterxml.jackson.annotation.JsonProperty("packSize") - val packSize: kotlin.Int = 0 -) : Pet(petType = petType) - diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt deleted file mode 100644 index 1311dc6d56ff..000000000000 --- a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Basic polymorphism example with discriminator - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. -*/ -package org.openapitools.server.models - -import org.openapitools.server.models.Cat -import org.openapitools.server.models.Dog - -/** - * - * @param petType - */ -@com.fasterxml.jackson.annotation.JsonTypeInfo(use = com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME, include = com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) -@com.fasterxml.jackson.annotation.JsonSubTypes( - com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = Cat::class, name = "cat"), - com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = Dog::class, name = "dog") -) -sealed class Pet( - - @field:com.fasterxml.jackson.annotation.JsonProperty("petType") - open val petType: kotlin.String - -) - From 9cc5d3724920f6bdd1de7889aa692d0b4561d8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 13:09:57 +0100 Subject: [PATCH 23/24] add files --- .../kotlin/org/openapitools/server/Main.kt | 16 +++++++ .../org/openapitools/server/models/Cat.kt | 42 +++++++++++++++++++ .../org/openapitools/server/models/Dog.kt | 29 +++++++++++++ .../org/openapitools/server/models/Pet.kt | 32 ++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt create mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt create mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt create mode 100644 samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt new file mode 100644 index 000000000000..dba7f137ec60 --- /dev/null +++ b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/Main.kt @@ -0,0 +1,16 @@ +package org.openapitools.server + +import io.javalin.Javalin +import io.javalin.apibuilder.ApiBuilder.* + + +fun main() { + + val app = Javalin + .create { config -> + config.router.apiBuilder { + } + } + + app.start() +} diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt new file mode 100644 index 000000000000..99ab4e0f3f50 --- /dev/null +++ b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Cat.kt @@ -0,0 +1,42 @@ +/** + * Basic polymorphism example with discriminator + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. +*/ +package org.openapitools.server.models + + +/** + * A pet cat + * @param huntingSkill The measured skill for hunting + * @param petType + */ +data class Cat( + /* The measured skill for hunting */ + + @field:com.fasterxml.jackson.annotation.JsonProperty("huntingSkill") + val huntingSkill: Cat.HuntingSkill, + + @field:com.fasterxml.jackson.annotation.JsonProperty("petType") + override val petType: kotlin.String = "cat", + +) : Pet(petType = petType) +{ + /** + * The measured skill for hunting + * Values: clueless,lazy,adventurous,aggressive + */ + enum class HuntingSkill(val value: kotlin.String){ + clueless("clueless"), + lazy("lazy"), + adventurous("adventurous"), + aggressive("aggressive"); + } +} + diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt new file mode 100644 index 000000000000..9f3cbe860d93 --- /dev/null +++ b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Dog.kt @@ -0,0 +1,29 @@ +/** + * Basic polymorphism example with discriminator + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. +*/ +package org.openapitools.server.models + + +/** + * A pet dog + * @param petType + * @param packSize the size of the pack the dog is from + */ +data class Dog( + + @field:com.fasterxml.jackson.annotation.JsonProperty("petType") + override val petType: kotlin.String = "dog", + /* the size of the pack the dog is from */ + + @field:com.fasterxml.jackson.annotation.JsonProperty("packSize") + val packSize: kotlin.Int = 0 +) : Pet(petType = petType) + diff --git a/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt new file mode 100644 index 000000000000..1311dc6d56ff --- /dev/null +++ b/samples/server/others/kotlin-server/polymorphism-and-discriminator/src/main/kotlin/org/openapitools/server/models/Pet.kt @@ -0,0 +1,32 @@ +/** + * Basic polymorphism example with discriminator + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. +*/ +package org.openapitools.server.models + +import org.openapitools.server.models.Cat +import org.openapitools.server.models.Dog + +/** + * + * @param petType + */ +@com.fasterxml.jackson.annotation.JsonTypeInfo(use = com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME, include = com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@com.fasterxml.jackson.annotation.JsonSubTypes( + com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = Cat::class, name = "cat"), + com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = Dog::class, name = "dog") +) +sealed class Pet( + + @field:com.fasterxml.jackson.annotation.JsonProperty("petType") + open val petType: kotlin.String + +) + From f6a2a8b4d82683afd7b4c823f62879cd09b9c6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Metli=C4=8Dka?= Date: Fri, 13 Feb 2026 14:22:00 +0100 Subject: [PATCH 24/24] trigger test rerun --- .../codegen/kotlin/spring/KotlinSpringServerCodegenTest.java | 1 - 1 file changed, 1 deletion(-) 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 b7bdcbf79d65..353c5141c910 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 @@ -3971,7 +3971,6 @@ public void springPaginatedWithSpringDocPrependsToExistingAnnotationArray() thro Map files = generateFromContract("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml", additionalProperties); - File petApi = files.get("PetApi.kt"); String content = Files.readString(petApi.toPath());