diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/VendorExtension.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/VendorExtension.java index 9be773475f2c..550a7c6d80a2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/VendorExtension.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/VendorExtension.java @@ -19,6 +19,7 @@ public enum VendorExtension { X_SETTER_EXTRA_ANNOTATION("x-setter-extra-annotation", ExtensionLevel.FIELD, "Custom annotation that can be specified over java setter for specific field", "When field is array & uniqueItems, then this extension is used to add `@JsonDeserialize(as = LinkedHashSet.class)` over setter, otherwise no value"), X_WEBCLIENT_BLOCKING("x-webclient-blocking", ExtensionLevel.OPERATION, "Specifies if method for specific operation should be blocking or non-blocking(ex: return `Mono/Flux` or `return T/List/Set` & execute `.block()` inside generated method)", "false"), X_WEBCLIENT_RETURN_EXCEPT_LIST_OF_STRING("x-webclient-return-except-list-of-string", ExtensionLevel.OPERATION, "Specifies if method for specific operation should return the type except List and Set(ex: return type expect the `Mono>/Flux>` and `Mono>/Flux>`)", "false"), + X_REACTIVE_RETURN_EXCEPT_LIST_OF_STRING("x-reactive-return-except-list-of-string", ExtensionLevel.OPERATION, "Specifies if method for specific operation should return the type except List and Set(ex: return type expect the `Mono>/Flux>` and `Mono>/Flux>`)", "false"), X_TAGS("x-tags", ExtensionLevel.OPERATION, "Specify multiple swagger tags for operation", null), X_ACCEPTS("x-accepts", ExtensionLevel.OPERATION, "Specify custom value for 'Accept' header for operation", null), X_CONTENT_TYPE("x-content-type", ExtensionLevel.OPERATION, "Specify custom value for 'Content-Type' header for operation", null), diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 2104047f125c..a8f1c0899b4f 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -1026,6 +1026,12 @@ public void setIsVoid(boolean isVoid) { prepareVersioningParameters(ops); handleImplicitHeaders(operation); + + if (isLibrary(SPRING_HTTP_INTERFACE) || isLibrary(SPRING_BOOT)) { + if (operation.isArray && "string".equalsIgnoreCase(operation.returnBaseType)) { + operation.vendorExtensions.put(VendorExtension.X_REACTIVE_RETURN_EXCEPT_LIST_OF_STRING.getName(), true); + } + } } // The tag for the controller is the first tag of the first operation final CodegenOperation firstOperation = ops.get(0); diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/responseType.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/responseType.mustache index a25da6310b56..378585299a50 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/responseType.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/responseType.mustache @@ -1 +1 @@ -{{^vendorExtensions.x-sse}}{{#reactive}}{{#useResponseEntity}}MonoreturnTypes}}{{#isArray}}>{{/isArray}}>>{{/useResponseEntity}}{{^useResponseEntity}}{{#isArray}}Flux{{/isArray}}{{^isArray}}Mono{{/isArray}}<{{>returnTypes}}>{{/useResponseEntity}}{{/reactive}}{{^reactive}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}{{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{#responseWrapper}}>{{/responseWrapper}}{{/reactive}}{{/vendorExtensions.x-sse}}{{#vendorExtensions.x-sse}}{{#isArray}}Flux{{/isArray}}{{^isArray}}Mono{{/isArray}}<{{>returnTypes}}>{{/vendorExtensions.x-sse}} \ No newline at end of file +{{^vendorExtensions.x-sse}}{{#reactive}}{{#useResponseEntity}}{{#vendorExtensions.x-reactive-return-except-list-of-string}}MonoreturnTypes}}>>>{{/vendorExtensions.x-reactive-return-except-list-of-string}}{{^vendorExtensions.x-reactive-return-except-list-of-string}}MonoreturnTypes}}{{#isArray}}>{{/isArray}}>>{{/vendorExtensions.x-reactive-return-except-list-of-string}}{{/useResponseEntity}}{{^useResponseEntity}}{{#vendorExtensions.x-reactive-return-except-list-of-string}}Mono<{{{returnContainer}}}<{{>returnTypes}}>>{{/vendorExtensions.x-reactive-return-except-list-of-string}}{{^vendorExtensions.x-reactive-return-except-list-of-string}}{{#isArray}}Flux{{/isArray}}{{^isArray}}Mono{{/isArray}}<{{>returnTypes}}>{{/vendorExtensions.x-reactive-return-except-list-of-string}}{{/useResponseEntity}}{{/reactive}}{{^reactive}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}{{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{#responseWrapper}}>{{/responseWrapper}}{{/reactive}}{{/vendorExtensions.x-sse}}{{#vendorExtensions.x-sse}}{{#vendorExtensions.x-reactive-return-except-list-of-string}}{{{returnContainer}}}<{{>returnTypes}}>{{/vendorExtensions.x-reactive-return-except-list-of-string}}{{^vendorExtensions.x-reactive-return-except-list-of-string}}{{#isArray}}Flux{{/isArray}}{{^isArray}}Mono{{/isArray}}<{{>returnTypes}}>{{/vendorExtensions.x-reactive-return-except-list-of-string}}{{/vendorExtensions.x-sse}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 14b541cf9f0c..7d14092792d5 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -8132,4 +8132,138 @@ void schemaMappingWithNullableAllOfRendersNullableJavaProperty() throws IOExcept JavaFileAssert.assertThat(files.get("MyObject.java")) .assertProperty("optionalRef").withType("JsonNullable"); } + + @Test + public void testReactiveSpringSupportListOfStringReturnType() throws IOException { + Map properties = new HashMap<>(); + properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api"); + properties.put(SpringCodegen.REACTIVE, true); + + + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("spring") + .setLibrary(SPRING_BOOT) + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/bugs/issue_7118.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + validateJavaSourceFiles(files); + + Path userApi = Paths.get(output + "/src/main/java/xyz/abcdef/api/UsersApi.java"); + + TestUtils.assertFileContains(userApi, + // list of string + "Mono>> getUserIdList", + // set of string + "Mono>> getUserIdSet" + ); + } + + @Test + public void testReactiveSpringSupportListOfStringReturnTypeNoResponseEntity() throws IOException { + Map properties = new HashMap<>(); + properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api"); + properties.put(SpringCodegen.REACTIVE, true); + properties.put(USE_RESPONSE_ENTITY, false); + + + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("spring") + .setLibrary(SPRING_BOOT) + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/bugs/issue_7118.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + validateJavaSourceFiles(files); + + Path userApi = Paths.get(output + "/src/main/java/xyz/abcdef/api/UsersApi.java"); + + TestUtils.assertFileContains(userApi, + // list of string + "Mono> getUserIdList", + // set of string + "Mono> getUserIdSet" + ); + } + + @Test + public void testReactiveSpringHttpInterfaceSupportListOfStringReturnType() throws IOException { + Map properties = new HashMap<>(); + properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api"); + properties.put(SpringCodegen.REACTIVE, true); + + + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("spring") + .setLibrary(SPRING_HTTP_INTERFACE) + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/bugs/issue_7118.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + validateJavaSourceFiles(files); + + Path userApi = Paths.get(output + "/src/main/java/xyz/abcdef/api/UsersApi.java"); + + TestUtils.assertFileContains(userApi, + // list of string + "Mono>> getUserIdList", + // set of string + "Mono>> getUserIdSet" + ); + } + + @Test + public void testReactiveSpringHttpInterfaceSupportListOfStringReturnTypeNoResponseEntity() throws IOException { + Map properties = new HashMap<>(); + properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api"); + properties.put(SpringCodegen.REACTIVE, true); + properties.put(USE_RESPONSE_ENTITY, false); + + + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("spring") + .setLibrary(SPRING_HTTP_INTERFACE) + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/bugs/issue_7118.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + validateJavaSourceFiles(files); + + Path userApi = Paths.get(output + "/src/main/java/xyz/abcdef/api/UsersApi.java"); + + TestUtils.assertFileContains(userApi, + // list of string + "Mono> getUserIdList", + // set of string + "Mono> getUserIdSet" + ); + } } \ No newline at end of file