diff --git a/docs/generators/java.md b/docs/generators/java.md index 651f4160754..fdbe518090d 100644 --- a/docs/generators/java.md +++ b/docs/generators/java.md @@ -52,6 +52,7 @@ sidebar_label: java |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |sourceFolder|source folder for generated code| |src/main/java| |supportJava6|Whether to support Java6 with the Jersey1 library. This option has been deprecated and will be removed in the 5.x release| |false| +|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk. Available on resttemplate library| |false| |useBeanValidation|Use BeanValidation API annotations| |false| |useGzipFeature|Send gzip-encoded requests| |false| |usePlayWS|Use Play! Async HTTP client (Play WS API)| |false| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java index fa818567284..797bec2c878 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java @@ -60,6 +60,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen public static final String USE_RUNTIME_EXCEPTION = "useRuntimeException"; public static final String USE_REFLECTION_EQUALS_HASHCODE = "useReflectionEqualsHashCode"; public static final String CASE_INSENSITIVE_RESPONSE_HEADERS = "caseInsensitiveResponseHeaders"; + public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles"; public static final String PLAY_24 = "play24"; public static final String PLAY_25 = "play25"; @@ -99,6 +100,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen protected boolean useRuntimeException = false; protected boolean useReflectionEqualsHashCode = false; protected boolean caseInsensitiveResponseHeaders = false; + protected boolean useAbstractionForFiles = false; protected String authFolder; protected String serializationLibrary = null; @@ -140,6 +142,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen cliOptions.add(CliOption.newBoolean(ASYNC_NATIVE, "If true, async handlers will be used, instead of the sync version")); cliOptions.add(CliOption.newBoolean(USE_REFLECTION_EQUALS_HASHCODE, "Use org.apache.commons.lang3.builder for equals and hashCode in the models. WARNING: This will fail under a security manager, unless the appropriate permissions are set up correctly and also there's potential performance impact.")); cliOptions.add(CliOption.newBoolean(CASE_INSENSITIVE_RESPONSE_HEADERS, "Make API response's headers case-insensitive. Available on " + OKHTTP_GSON + ", " + JERSEY2 + " libraries")); + cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk. Available on " + RESTTEMPLATE + " library")); supportedLibraries.put(JERSEY1, "HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.x. Enable Java6 support using '-DsupportJava6=true'. Enable gzip request encoding using '-DuseGzipFeature=true'. IMPORTANT NOTE: jersey 1.x is no longer actively maintained so please upgrade to 'jersey2' or other HTTP libaries instead."); supportedLibraries.put(JERSEY2, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x"); @@ -285,6 +288,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen this.setUseReflectionEqualsHashCode(convertPropertyToBooleanAndWriteBack(CASE_INSENSITIVE_RESPONSE_HEADERS)); } + if (additionalProperties.containsKey(USE_ABSTRACTION_FOR_FILES)) { + this.setUseAbstractionForFiles(convertPropertyToBooleanAndWriteBack(USE_ABSTRACTION_FOR_FILES)); + } + final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/"); final String apiFolder = (sourceFolder + '/' + apiPackage).replace(".", "/"); authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/"); @@ -864,6 +871,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen this.caseInsensitiveResponseHeaders = caseInsensitiveResponseHeaders; } + public void setUseAbstractionForFiles(boolean useAbstractionForFiles) { + this.useAbstractionForFiles = useAbstractionForFiles; + } + /** * Serialization library. * diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api.mustache index 2f1ed68e996..9c7a4fc703c 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api.mustache @@ -73,7 +73,7 @@ public class {{classname}} { {{#isDeprecated}} @Deprecated {{/isDeprecated}} - public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException { + public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}org.springframework.core.io.AbstractResource{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException { {{#returnType}} return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}).getBody(); {{/returnType}} @@ -101,7 +101,7 @@ public class {{classname}} { {{#isDeprecated}} @Deprecated {{/isDeprecated}} - public ResponseEntity<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException { + public ResponseEntity<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}org.springframework.core.io.AbstractResource{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException { Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; {{#allParams}}{{#required}} // verify the required parameter '{{paramName}}' is set @@ -131,7 +131,7 @@ public class {{classname}} { {{/hasMore}}{{/cookieParams}}{{/hasCookieParams}}{{#hasFormParams}} {{#formParams}}if ({{paramName}} != null) - formParams.{{^collectionFormat}}add{{/collectionFormat}}{{#collectionFormat}}put{{/collectionFormat}}("{{baseName}}", {{#isFile}}{{^collectionFormat}}new FileSystemResource({{paramName}}){{/collectionFormat}}{{/isFile}}{{#isFile}}{{#collectionFormat}}{{paramName}}.stream().map(FileSystemResource::new).collect(Collectors.toList()){{/collectionFormat}}{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}});{{#hasMore}} + formParams.{{^collectionFormat}}add{{/collectionFormat}}{{#collectionFormat}}put{{/collectionFormat}}("{{baseName}}", {{#isFile}}{{^collectionFormat}}{{#useAbstractionForFiles}}{{paramName}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}new FileSystemResource({{paramName}}){{/useAbstractionForFiles}}{{/collectionFormat}}{{/isFile}}{{#isFile}}{{#collectionFormat}}{{paramName}}.stream(){{^useAbstractionForFiles}}.map(FileSystemResource::new){{/useAbstractionForFiles}}.collect(Collectors.toList()){{/collectionFormat}}{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}});{{#hasMore}} {{/hasMore}}{{/formParams}}{{/hasFormParams}} final String[] accepts = { {{#hasProduces}} diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api_test.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api_test.mustache index 127ac2defc5..f69cf40ec3e 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api_test.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api_test.mustache @@ -34,7 +34,7 @@ public class {{classname}}Test { @Test public void {{operationId}}Test() { {{#allParams}} - {{{dataType}}} {{paramName}} = null; + {{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}org.springframework.core.io.AbstractResource{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}} = null; {{/allParams}} {{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/TestUtils.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/TestUtils.java index d554a8ee7d9..96d01ab2aad 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/TestUtils.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/TestUtils.java @@ -166,7 +166,7 @@ public class TestUtils { String file = linearize(generatedFile); assertNotNull(file); for (String line : lines) - assertTrue(file.contains(linearize(line))); + assertTrue(file.contains(linearize(line)), "File does not contain line [" + line + "]"); } catch (IOException e) { fail("Unable to evaluate file " + path.toString()); } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index 69ead62d141..8c2d17792f5 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -927,4 +927,50 @@ public class JavaClientCodegenTest { ); } + /** + * See https://github.com/OpenAPITools/openapi-generator/issues/6715 + */ + @Test + public void testRestTemplateWithUseAbstractionForFiles() throws IOException { + + Map properties = new HashMap<>(); + properties.put(JavaClientCodegen.JAVA8_MODE, true); + properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api"); + properties.put(JavaClientCodegen.USE_ABSTRACTION_FOR_FILES, true); + + + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("java") + .setLibrary(JavaClientCodegen.RESTTEMPLATE) + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/form-multipart-binary-array.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + + Path defaultApi = Paths.get(output + "/src/main/java/xyz/abcdef/api/MultipartApi.java"); + TestUtils.assertFileContains(defaultApi, + //multiple files + "multipartArray(java.util.Collection files)", + "multipartArrayWithHttpInfo(java.util.Collection files)", + "formParams.put(\"files\", files.stream().collect(Collectors.toList()));", + + //mixed + "multipartMixed(org.springframework.core.io.AbstractResource file, MultipartMixedMarker marker)", + "multipartMixedWithHttpInfo(org.springframework.core.io.AbstractResource file, MultipartMixedMarker marker)", + "formParams.add(\"file\", file);", + + //single file + "multipartSingle(org.springframework.core.io.AbstractResource file)", + "multipartSingleWithHttpInfo(org.springframework.core.io.AbstractResource file)", + "formParams.add(\"file\", file);" + ); + } }