Skip to content

Commit c52cc1f

Browse files
authored
[kotlin-spring][server] Feat: Make it possible to include "HttpServletRequest" or "ServerWebExchange" as a method parameter in controller interfaces and/or implementations (#22263)
* modify templates to enable possibility to add reactive or blocking request context * add logic to enable additional property * regenerate files * regenerate documentation * revert unrelated formatting changes * revert commented out code * add tests * refactor test to DRY them a bit * move tests around * increase tests coverage * fix for delegate * fix for delegate - and refactor tests * fix tests * refactor tests * add tests for delegate * add kotlin project compile check test for include-http-request-context * fix * fix * fix output folder naming. Add the sample to github action config file. * add missing interfaces to fix compilation * regenerate samples * fix also api_test.mustache to enable testing * add tests for generated tests
1 parent 2c7efda commit c52cc1f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+3386
-114
lines changed

.github/workflows/samples-kotlin-server.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
- samples/server/petstore/kotlin-springboot-source-swagger2
4040
- samples/server/petstore/kotlin-springboot-springfox
4141
- samples/server/petstore/kotlin-springboot-x-kotlin-implements
42+
- samples/server/petstore/kotlin-springboot-include-http-request-context-delegate
4243
- samples/server/petstore/kotlin-server/ktor
4344
- samples/server/petstore/kotlin-server/ktor2
4445
- samples/server/petstore/kotlin-server/jaxrs-spec
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
generatorName: kotlin-spring
2+
outputDir: samples/server/petstore/kotlin-springboot-include-http-request-context-delegate
3+
library: spring-boot
4+
inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/kotlin-spring
6+
additionalProperties:
7+
documentationProvider: none
8+
annotationLibrary: swagger1
9+
useSwaggerUI: false
10+
serviceImplementation: false
11+
skipDefaultInterface: true
12+
interfaceOnly: false
13+
serializableModel: true
14+
beanValidations: true
15+
includeHttpRequestContext: true
16+
reactive: true
17+
delegatePattern: true

bin/configs/kotlin-spring-boot-x-kotlin-implements.yaml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with
55
templateDir: modules/openapi-generator/src/main/resources/kotlin-spring
66
additionalProperties:
77
documentationProvider: none
8-
annotationLibrary: none
9-
useSwaggerUI: "false"
10-
serviceImplementation: "false"
11-
skipDefaultInterface: "true"
12-
interfaceOnly: "true"
13-
serializableModel: "true"
14-
beanValidations: "true"
8+
annotationLibrary: swagger1
9+
useSwaggerUI: false
10+
serviceImplementation: false
11+
skipDefaultInterface: true
12+
interfaceOnly: true
13+
serializableModel: true
14+
beanValidations: true
15+
includeHttpRequestContext: true

docs/generators/kotlin-spring.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
3535
|exceptionHandler|generate default global exception handlers (not compatible with reactive. enabling reactive will disable exceptionHandler )| |true|
3636
|gradleBuildFile|generate a gradle build file using the Kotlin DSL| |true|
3737
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
38+
|includeHttpRequestContext|Whether to include HttpServletRequest (blocking) or ServerWebExchange (reactive) as additional parameter in generated methods.| |false|
3839
|interfaceOnly|Whether to generate only API interface stubs without the server files.| |false|
3940
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dt>**spring-cloud**</dt><dd>Spring-Cloud-Feign client with Spring-Boot auto-configured settings.</dd><dt>**spring-declarative-http-interface**</dt><dd>Spring Declarative Interface client</dd></dl>|spring-boot|
4041
|modelMutable|Create mutable models| |false|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
8989
public static final String DECLARATIVE_INTERFACE_REACTIVE_MODE = "declarativeInterfaceReactiveMode";
9090

9191
public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
92+
public static final String INCLUDE_HTTP_REQUEST_CONTEXT = "includeHttpRequestContext";
9293
public static final String USE_FLOW_FOR_ARRAY_RETURN_TYPE = "useFlowForArrayReturnType";
9394
public static final String REQUEST_MAPPING_OPTION = "requestMappingMode";
9495
public static final String USE_REQUEST_MAPPING_ON_CONTROLLER = "useRequestMappingOnController";
@@ -144,6 +145,7 @@ public String getDescription() {
144145
@Setter private boolean serviceImplementation = false;
145146
@Getter @Setter
146147
private boolean reactive = false;
148+
@Setter private boolean includeHttpRequestContext = false;
147149
@Getter @Setter
148150
private boolean useFlowForArrayReturnType = true;
149151
@Setter private boolean interfaceOnly = false;
@@ -239,6 +241,7 @@ public KotlinSpringServerCodegen() {
239241
" (contexts) added to single project.", beanQualifiers);
240242
addSwitch(USE_SPRING_BOOT3, "Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.", useSpringBoot3);
241243
addSwitch(USE_FLOW_FOR_ARRAY_RETURN_TYPE, "Whether to use Flow for array/collection return types when reactive is enabled. If false, will use List instead.", useFlowForArrayReturnType);
244+
addSwitch(INCLUDE_HTTP_REQUEST_CONTEXT, "Whether to include HttpServletRequest (blocking) or ServerWebExchange (reactive) as additional parameter in generated methods.", includeHttpRequestContext);
242245
addSwitch(DECLARATIVE_INTERFACE_WRAP_RESPONSES,
243246
"Whether (when false) to return actual type (e.g. List<Fruit>) and handle non 2xx responses via exceptions or (when true) return entire ResponseEntity (e.g. ResponseEntity<List<Fruit>>)",
244247
declarativeInterfaceWrapResponses);
@@ -631,6 +634,9 @@ public void processOpts() {
631634
if (additionalProperties.containsKey(USE_SPRING_BOOT3)) {
632635
this.setUseSpringBoot3(convertPropertyToBoolean(USE_SPRING_BOOT3));
633636
}
637+
if (additionalProperties.containsKey(INCLUDE_HTTP_REQUEST_CONTEXT)) {
638+
this.setIncludeHttpRequestContext(convertPropertyToBoolean(INCLUDE_HTTP_REQUEST_CONTEXT));
639+
}
634640
if (isUseSpringBoot3()) {
635641
if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) {
636642
throw new IllegalArgumentException(DocumentationProvider.SPRINGFOX.getPropertyName() + " is not supported with Spring Boot > 3.x");

modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v
8989
produces = [{{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}}]{{/hasProduces}}{{#hasConsumes}},
9090
consumes = [{{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}}]{{/hasConsumes}}{{/singleContentTypes}}
9191
)
92-
{{#reactive}}{{^isArray}}suspend {{/isArray}}{{#isArray}}{{^useFlowForArrayReturnType}}suspend {{/useFlowForArrayReturnType}}{{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}): ResponseEntity<{{>returnTypes}}> {
92+
{{#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}}): ResponseEntity<{{>returnTypes}}> {
9393
return {{>returnValue}}
9494
}
9595
{{/operation}}

modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ interface {{classname}}Delegate {
3434
* @see {{classname}}#{{operationId}}
3535
*/
3636
{{#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}},
37-
{{/-last}}{{/allParams}}): {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}}{{^skipDefaultDelegateInterface}} {
37+
{{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}},
38+
{{/hasParams}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}): {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}}{{^skipDefaultDelegateInterface}} {
3839
{{>methodBody}}{{! prevent indent}}
3940
}{{/skipDefaultDelegateInterface}}
4041

modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ interface {{classname}} {
102102
produces = [{{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}}]{{/hasProduces}}{{#hasConsumes}},
103103
consumes = [{{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}}]{{/hasConsumes}}{{/singleContentTypes}}
104104
)
105-
{{#reactive}}{{^isArray}}suspend {{/isArray}}{{#isArray}}{{^useFlowForArrayReturnType}}suspend {{/useFlowForArrayReturnType}}{{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}): ResponseEntity<{{>returnTypes}}>{{^skipDefaultApiInterface}} {
105+
{{#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}}): ResponseEntity<{{>returnTypes}}>{{^skipDefaultApiInterface}} {
106106
{{^isDelegate}}
107107
return {{>returnValue}}
108108
{{/isDelegate}}
109109
{{#isDelegate}}
110-
return getDelegate().{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
110+
return getDelegate().{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}request{{/reactive}}{{/includeHttpRequestContext}})
111111
{{/isDelegate}}
112112
}{{/skipDefaultApiInterface}}
113113
{{/operation}}

modules/openapi-generator/src/main/resources/kotlin-spring/api_test.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class {{classname}}Test {
2929
{{#allParams}}
3030
val {{{paramName}}}: {{>optionalDataType}} = TODO()
3131
{{/allParams}}
32-
val response: ResponseEntity<{{>returnTypes}}> = api.{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
32+
{{#includeHttpRequestContext}}val {{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}} = TODO(){{/includeHttpRequestContext}}
33+
val response: ResponseEntity<{{>returnTypes}}> = api.{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}request{{/reactive}}{{/includeHttpRequestContext}})
3334

3435
// TODO: test validations
3536
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/TestUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public static void assertFileContains(Path path, String... lines) {
173173
String file = linearize(generatedFile);
174174
assertNotNull(file);
175175
for (String line : lines)
176-
assertTrue(file.contains(linearize(line)), "File does not contain line [" + line + "]");
176+
assertTrue(file.contains(linearize(line)), "File '" + path + "' does not contain line [" + line + "]");
177177
} catch (IOException e) {
178178
fail("Unable to evaluate file " + path);
179179
}

0 commit comments

Comments
 (0)