[Java][RestTemplate] Use abstraction for files (#6912)

* Fix dir path in PR request template

* Add "useAbstractionForFiles" config option for Java/RestTemplate to allow flexible options in generated client when a file is needed (#6715)

* Add "useAbstractionForFiles" config option for Java/RestTemplate to allow flexible options in generated client when a file is needed (#6715)

* Add "useAbstractionForFiles" config option for Java/RestTemplate to allow flexible options in generated client when a file is needed (#6715)

* #6715 - Add "useAbstractionForFiles" config option for Java/RestTemplate to allow flexible options in generated client when a file is needed.
This commit is contained in:
Moshe Elisha 2020-07-20 17:54:14 +03:00 committed by GitHub
parent 95bd845f79
commit 0a394bc883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 5 deletions

View File

@ -52,6 +52,7 @@ sidebar_label: java
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|sourceFolder|source folder for generated code| |src/main/java| |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| |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| |useBeanValidation|Use BeanValidation API annotations| |false|
|useGzipFeature|Send gzip-encoded requests| |false| |useGzipFeature|Send gzip-encoded requests| |false|
|usePlayWS|Use Play! Async HTTP client (Play WS API)| |false| |usePlayWS|Use Play! Async HTTP client (Play WS API)| |false|

View File

@ -60,6 +60,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public static final String USE_RUNTIME_EXCEPTION = "useRuntimeException"; public static final String USE_RUNTIME_EXCEPTION = "useRuntimeException";
public static final String USE_REFLECTION_EQUALS_HASHCODE = "useReflectionEqualsHashCode"; public static final String USE_REFLECTION_EQUALS_HASHCODE = "useReflectionEqualsHashCode";
public static final String CASE_INSENSITIVE_RESPONSE_HEADERS = "caseInsensitiveResponseHeaders"; 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_24 = "play24";
public static final String PLAY_25 = "play25"; public static final String PLAY_25 = "play25";
@ -99,6 +100,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
protected boolean useRuntimeException = false; protected boolean useRuntimeException = false;
protected boolean useReflectionEqualsHashCode = false; protected boolean useReflectionEqualsHashCode = false;
protected boolean caseInsensitiveResponseHeaders = false; protected boolean caseInsensitiveResponseHeaders = false;
protected boolean useAbstractionForFiles = false;
protected String authFolder; protected String authFolder;
protected String serializationLibrary = null; 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(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(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(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(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"); 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)); 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 invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");
final String apiFolder = (sourceFolder + '/' + apiPackage).replace(".", "/"); final String apiFolder = (sourceFolder + '/' + apiPackage).replace(".", "/");
authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/"); authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/");
@ -864,6 +871,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen
this.caseInsensitiveResponseHeaders = caseInsensitiveResponseHeaders; this.caseInsensitiveResponseHeaders = caseInsensitiveResponseHeaders;
} }
public void setUseAbstractionForFiles(boolean useAbstractionForFiles) {
this.useAbstractionForFiles = useAbstractionForFiles;
}
/** /**
* Serialization library. * Serialization library.
* *

View File

@ -73,7 +73,7 @@ public class {{classname}} {
{{#isDeprecated}} {{#isDeprecated}}
@Deprecated @Deprecated
{{/isDeprecated}} {{/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<org.springframework.core.io.AbstractResource>{{/collectionFormat}}{{^collectionFormat}}org.springframework.core.io.AbstractResource{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws RestClientException {
{{#returnType}} {{#returnType}}
return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}).getBody(); return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}).getBody();
{{/returnType}} {{/returnType}}
@ -101,7 +101,7 @@ public class {{classname}} {
{{#isDeprecated}} {{#isDeprecated}}
@Deprecated @Deprecated
{{/isDeprecated}} {{/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<org.springframework.core.io.AbstractResource>{{/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}}; Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
{{#allParams}}{{#required}} {{#allParams}}{{#required}}
// verify the required parameter '{{paramName}}' is set // verify the required parameter '{{paramName}}' is set
@ -131,7 +131,7 @@ public class {{classname}} {
{{/hasMore}}{{/cookieParams}}{{/hasCookieParams}}{{#hasFormParams}} {{/hasMore}}{{/cookieParams}}{{/hasCookieParams}}{{#hasFormParams}}
{{#formParams}}if ({{paramName}} != null) {{#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}} {{/hasMore}}{{/formParams}}{{/hasFormParams}}
final String[] accepts = { {{#hasProduces}} final String[] accepts = { {{#hasProduces}}

View File

@ -34,7 +34,7 @@ public class {{classname}}Test {
@Test @Test
public void {{operationId}}Test() { public void {{operationId}}Test() {
{{#allParams}} {{#allParams}}
{{{dataType}}} {{paramName}} = null; {{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<org.springframework.core.io.AbstractResource>{{/collectionFormat}}{{^collectionFormat}}org.springframework.core.io.AbstractResource{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}} = null;
{{/allParams}} {{/allParams}}
{{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); {{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});

View File

@ -166,7 +166,7 @@ public class TestUtils {
String file = linearize(generatedFile); String file = linearize(generatedFile);
assertNotNull(file); assertNotNull(file);
for (String line : lines) for (String line : lines)
assertTrue(file.contains(linearize(line))); assertTrue(file.contains(linearize(line)), "File does not contain line [" + line + "]");
} catch (IOException e) { } catch (IOException e) {
fail("Unable to evaluate file " + path.toString()); fail("Unable to evaluate file " + path.toString());
} }

View File

@ -927,4 +927,50 @@ public class JavaClientCodegenTest {
); );
} }
/**
* See https://github.com/OpenAPITools/openapi-generator/issues/6715
*/
@Test
public void testRestTemplateWithUseAbstractionForFiles() throws IOException {
Map<String, Object> 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<File> 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<org.springframework.core.io.AbstractResource> files)",
"multipartArrayWithHttpInfo(java.util.Collection<org.springframework.core.io.AbstractResource> 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);"
);
}
} }