[Java] Add streaming endpoint support (#9813)

* add streaming endpoint support to java client

* update doc
This commit is contained in:
William Cheng 2021-10-24 16:02:49 +08:00 committed by GitHub
parent 1cd591bf7d
commit 8069d183f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 105 additions and 3 deletions

View File

@ -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| |sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
|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|
|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| |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|

View File

@ -63,6 +63,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public static final String MICROPROFILE_FRAMEWORK = "microprofileFramework"; public static final String MICROPROFILE_FRAMEWORK = "microprofileFramework";
public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles"; public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles";
public static final String DYNAMIC_OPERATIONS = "dynamicOperations"; 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 GRADLE_PROPERTIES= "gradleProperties";
public static final String PLAY_24 = "play24"; public static final String PLAY_24 = "play24";
@ -112,6 +113,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
protected boolean caseInsensitiveResponseHeaders = false; protected boolean caseInsensitiveResponseHeaders = false;
protected boolean useAbstractionForFiles = false; protected boolean useAbstractionForFiles = false;
protected boolean dynamicOperations = false; protected boolean dynamicOperations = false;
protected boolean supportStreaming = false;
protected String gradleProperties; protected String gradleProperties;
protected String authFolder; protected String authFolder;
protected String serializationLibrary = null; 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.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(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(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")); 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."); 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); 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)) { if (additionalProperties.containsKey(GRADLE_PROPERTIES)) {
this.setGradleProperties(additionalProperties.get(GRADLE_PROPERTIES).toString()); this.setGradleProperties(additionalProperties.get(GRADLE_PROPERTIES).toString());
} }
@ -992,6 +1000,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen
this.dynamicOperations = dynamicOperations; this.dynamicOperations = dynamicOperations;
} }
public void setSupportStreaming(final boolean supportStreaming) {
this.supportStreaming = supportStreaming;
}
public void setGradleProperties(final String gradleProperties) { public void setGradleProperties(final String gradleProperties) {
this.gradleProperties= gradleProperties; this.gradleProperties= gradleProperties;
} }

View File

@ -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)} * {@link #executeAsync(Call, Type, ApiCallback)}
* *

View File

@ -47,6 +47,9 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
{{#supportStreaming}}
import java.io.InputStream;
{{/supportStreaming}}
{{/fullJavaUtil}} {{/fullJavaUtil}}
{{#operations}} {{#operations}}
@ -247,10 +250,18 @@ public class {{classname}} {
{{#isDeprecated}} {{#isDeprecated}}
@Deprecated @Deprecated
{{/isDeprecated}} {{/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 { 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}} {{#returnType}}ApiResponse<{{{.}}}> localVarResp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}}
return localVarResp.getData();{{/returnType}} return localVarResp.getData();{{/returnType}}
} }
{{/vendorExtensions.x-streaming}}
{{/vendorExtensions.x-group-parameters}} {{/vendorExtensions.x-group-parameters}}
{{^vendorExtensions.x-group-parameters}}/** {{^vendorExtensions.x-group-parameters}}/**
@ -279,11 +290,17 @@ public class {{classname}} {
{{#isDeprecated}} {{#isDeprecated}}
@Deprecated @Deprecated
{{/isDeprecated}} {{/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); okhttp3.Call localVarCall = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null);
{{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); {{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType();
return localVarApiClient.execute(localVarCall, localVarReturnType);{{/returnType}}{{^returnType}}return localVarApiClient.execute(localVarCall);{{/returnType}} return localVarApiClient.execute(localVarCall, localVarReturnType);{{/returnType}}{{^returnType}}return localVarApiClient.execute(localVarCall);{{/returnType}}
} }
{{/vendorExtensions.x-streaming}}
{{^vendorExtensions.x-group-parameters}}/** {{^vendorExtensions.x-group-parameters}}/**
* {{summary}} (asynchronously) * {{summary}} (asynchronously)

View File

@ -13,6 +13,9 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
{{#supportStreaming}}
import java.io.InputStream;
{{/supportStreaming}}
{{/fullJavaUtil}} {{/fullJavaUtil}}
/** /**
@ -37,10 +40,16 @@ public class {{classname}}Test {
{{#allParams}} {{#allParams}}
{{{dataType}}} {{paramName}} = null; {{{dataType}}} {{paramName}} = null;
{{/allParams}} {{/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}} .{{paramName}}({{paramName}}){{/optionalParams}}
.execute();{{/vendorExtensions.x-group-parameters}} .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 // TODO: test validations
} }
{{/operation}}{{/operations}} {{/operation}}{{/operations}}

View File

@ -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