diff --git a/docs/generators/java.md b/docs/generators/java.md index 5543c075639..efeaa5f8049 100644 --- a/docs/generators/java.md +++ b/docs/generators/java.md @@ -59,6 +59,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |sortModelPropertiesByRequiredFlag|Sort model properties 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| +|supportStreaming|Support streaming endpoint (beta)| |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| 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 c6234ea8824..967815a30d6 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 @@ -63,6 +63,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen public static final String MICROPROFILE_FRAMEWORK = "microprofileFramework"; public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles"; public static final String DYNAMIC_OPERATIONS = "dynamicOperations"; + public static final String SUPPORT_STREAMING = "supportStreaming"; public static final String GRADLE_PROPERTIES= "gradleProperties"; public static final String PLAY_24 = "play24"; @@ -112,6 +113,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen protected boolean caseInsensitiveResponseHeaders = false; protected boolean useAbstractionForFiles = false; protected boolean dynamicOperations = false; + protected boolean supportStreaming = false; protected String gradleProperties; protected String authFolder; protected String serializationLibrary = null; @@ -156,6 +158,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen cliOptions.add(CliOption.newString(MICROPROFILE_FRAMEWORK, "Framework for microprofile. Possible values \"kumuluzee\"")); 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")); cliOptions.add(CliOption.newBoolean(DYNAMIC_OPERATIONS, "Generate operations dynamically at runtime from an OAS", this.dynamicOperations)); + cliOptions.add(CliOption.newBoolean(SUPPORT_STREAMING, "Support streaming endpoint (beta)", this.supportStreaming)); cliOptions.add(CliOption.newString(GRADLE_PROPERTIES, "Append additional Gradle proeprties to the gradle.properties file")); supportedLibraries.put(JERSEY1, "HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.x. 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 libraries instead."); @@ -321,6 +324,11 @@ public class JavaClientCodegen extends AbstractJavaCodegen } additionalProperties.put(DYNAMIC_OPERATIONS, dynamicOperations); + if (additionalProperties.containsKey(SUPPORT_STREAMING)) { + this.setSupportStreaming(Boolean.parseBoolean(additionalProperties.get(SUPPORT_STREAMING).toString())); + } + additionalProperties.put(SUPPORT_STREAMING, supportStreaming); + if (additionalProperties.containsKey(GRADLE_PROPERTIES)) { this.setGradleProperties(additionalProperties.get(GRADLE_PROPERTIES).toString()); } @@ -992,6 +1000,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen this.dynamicOperations = dynamicOperations; } + public void setSupportStreaming(final boolean supportStreaming) { + this.supportStreaming = supportStreaming; + } + public void setGradleProperties(final String gradleProperties) { this.gradleProperties= gradleProperties; } diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache index ba47040542d..357d8c71d0c 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache @@ -1123,6 +1123,23 @@ public class ApiClient { } } + {{#supportStreaming}} + public InputStream executeStream(Call call, Type returnType) throws ApiException { + try { + Response response = call.execute(); + if (!response.isSuccessful()) { + throw new ApiException(response.code(), response.message()); + } + if (response.body() == null) { + return null; + } + return response.body().byteStream(); + } catch (IOException e) { + throw new ApiException(e); + } + } + + {{/supportStreaming}} /** * {@link #executeAsync(Call, Type, ApiCallback)} * diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api.mustache index 2a0f89e94f6..ba495cc72fe 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api.mustache @@ -47,6 +47,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +{{#supportStreaming}} +import java.io.InputStream; +{{/supportStreaming}} {{/fullJavaUtil}} {{#operations}} @@ -247,10 +250,18 @@ public class {{classname}} { {{#isDeprecated}} @Deprecated {{/isDeprecated}} + {{#vendorExtensions.x-streaming}} + public {{#returnType}}InputStream {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException { + {{#returnType}}InputStream localVarResp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}} + return localVarResp;{{/returnType}} + } + {{/vendorExtensions.x-streaming}} + {{^vendorExtensions.x-streaming}} public {{#returnType}}{{{.}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException { {{#returnType}}ApiResponse<{{{.}}}> localVarResp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}} return localVarResp.getData();{{/returnType}} } + {{/vendorExtensions.x-streaming}} {{/vendorExtensions.x-group-parameters}} {{^vendorExtensions.x-group-parameters}}/** @@ -279,11 +290,17 @@ public class {{classname}} { {{#isDeprecated}} @Deprecated {{/isDeprecated}} - public{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}private{{/vendorExtensions.x-group-parameters}} ApiResponse<{{{returnType}}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException { + public{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}private{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-streaming}} InputStream {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException { + okhttp3.Call localVarCall = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null); + {{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); + return localVarApiClient.executeStream(localVarCall, localVarReturnType);{{/returnType}} + } + {{/vendorExtensions.x-streaming}}{{^vendorExtensions.x-streaming}} ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException { okhttp3.Call localVarCall = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null); {{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); return localVarApiClient.execute(localVarCall, localVarReturnType);{{/returnType}}{{^returnType}}return localVarApiClient.execute(localVarCall);{{/returnType}} } + {{/vendorExtensions.x-streaming}} {{^vendorExtensions.x-group-parameters}}/** * {{summary}} (asynchronously) diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api_test.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api_test.mustache index 2daa8f44dda..98a30a60cd5 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api_test.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api_test.mustache @@ -13,6 +13,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +{{#supportStreaming}} +import java.io.InputStream; +{{/supportStreaming}} {{/fullJavaUtil}} /** @@ -37,10 +40,16 @@ public class {{classname}}Test { {{#allParams}} {{{dataType}}} {{paramName}} = null; {{/allParams}} - {{#returnType}}{{{.}}} response = {{/returnType}}api.{{operationId}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}} + {{#vendorExtensions.x-streaming}} + InputStream response = api.{{operationId}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}} .{{paramName}}({{paramName}}){{/optionalParams}} .execute();{{/vendorExtensions.x-group-parameters}} - + {{/vendorExtensions.x-streaming}} + {{^vendorExtensions.x-streaming}} + {{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}} + .{{paramName}}({{paramName}}){{/optionalParams}} + .execute();{{/vendorExtensions.x-group-parameters}} + {{/vendorExtensions.x-streaming}} // TODO: test validations } {{/operation}}{{/operations}} diff --git a/modules/openapi-generator/src/test/resources/3_0/streaming.yaml b/modules/openapi-generator/src/test/resources/3_0/streaming.yaml new file mode 100644 index 00000000000..e22bb54b40e --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/streaming.yaml @@ -0,0 +1,46 @@ +openapi: 3.0.1 +info: + title: ping some object + version: '1.0' +servers: + - url: 'http://localhost:8082/' +paths: + /ping: + post: + x-streaming: true + operationId: postPing + tags: + - ping + requestBody: + content: + 'application/json': + schema: + $ref: "#/components/schemas/SomeObj" + responses: + '200': + description: OK + content: + 'application/json': + schema: + $ref: "#/components/schemas/SomeObj" +components: + schemas: + SomeObj: + type: object + properties: + $_type: + type: string + # using 'enum' & 'default' for '$_type' is a work-around until constants are supported + # See https://github.com/OAI/OpenAPI-Specification/issues/1313 + enum: + - SomeObjIdentifier + default: SomeObjIdentifier + id: + type: integer + format: int64 + name: + type: string + active: + type: boolean + type: + type: string