Skip to content

Commit

Permalink
Java Jersey2: Make generated client code thread safe (#7605)
Browse files Browse the repository at this point in the history
* fix issue-7453; make jersey 2 generated code thread safe by following the withHttpInfo pattern used by many other generated clients

* fix issue-7453; make jersey 2 generated code thread safe by following the withHttpInfo pattern used by many other generated clients
  • Loading branch information
tsiq-karold authored and wing328 committed Feb 18, 2018
1 parent 35ec8ca commit cddcda0
Show file tree
Hide file tree
Showing 12 changed files with 545 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,11 @@ public void processOpts() {
if ("retrofit2".equals(getLibrary()) && !usePlayWS) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
}
} else if ("jersey2".equals(getLibrary()) || "resteasy".equals(getLibrary())) {
} else if ("jersey2".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
additionalProperties.put("jackson", "true");
} else if ("resteasy".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
additionalProperties.put("jackson", "true");
} else if("jersey1".equals(getLibrary())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ public class ApiClient {
protected Map<String, Authentication> authentications;
protected int statusCode;
protected Map<String, List<String>> responseHeaders;
protected DateFormat dateFormat;
public ApiClient() {
Expand Down Expand Up @@ -119,22 +116,6 @@ public class ApiClient {
return this;
}

/**
* Gets the status code of the previous request
* @return Status code
*/
public int getStatusCode() {
return statusCode;
}

/**
* Gets the response headers of the previous request
* @return Response headers
*/
public Map<String, List<String>> getResponseHeaders() {
return responseHeaders;
}

/**
* Get authentications (key: authentication name, value: authentication).
* @return Map of authentication object
Expand Down Expand Up @@ -669,7 +650,7 @@ public class ApiClient {
* @return The response body in type of string
* @throws ApiException API exception
*/
public <T> T invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
public <T> ApiResponse<T> invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
updateParamsForAuth(authNames, queryParams, headerParams);
// Not using `.target(this.basePath).path(path)` below,
Expand Down Expand Up @@ -724,16 +705,16 @@ public class ApiClient {
throw new ApiException(500, "unknown method type " + method);
}

statusCode = response.getStatusInfo().getStatusCode();
responseHeaders = buildResponseHeaders(response);
int statusCode = response.getStatusInfo().getStatusCode();
Map<String, List<String>> responseHeaders = buildResponseHeaders(response);

if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) {
return null;
return new ApiResponse<>(statusCode, responseHeaders);
} else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) {
if (returnType == null)
return null;
return new ApiResponse<>(statusCode, responseHeaders);
else
return deserialize(response, returnType);
return new ApiResponse<>(statusCode, responseHeaders, deserialize(response, returnType));
} else {
String message = "error";
String respBody = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{{>licenseInfo}}

package {{invokerPackage}};

import java.util.List;
import java.util.Map;

/**
* API response returned by API call.
*
* @param <T> The type of data that is deserialized from response body
*/
public class ApiResponse<T> {
private final int statusCode;
private final Map<String, List<String>> headers;
private final T data;
/**
* @param statusCode The status code of HTTP response
* @param headers The headers of HTTP response
*/
public ApiResponse(int statusCode, Map<String, List<String>> headers) {
this(statusCode, headers, null);
}

/**
* @param statusCode The status code of HTTP response
* @param headers The headers of HTTP response
* @param data The object deserialized from response bod
*/
public ApiResponse(int statusCode, Map<String, List<String>> headers, T data) {
this.statusCode = statusCode;
this.headers = headers;
this.data = data;
}

public int getStatusCode() {
return statusCode;
}

public Map<String, List<String>> getHeaders() {
return headers;
}

public T getData() {
return data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package {{package}};

import {{invokerPackage}}.ApiException;
import {{invokerPackage}}.ApiClient;
import {{invokerPackage}}.ApiResponse;
import {{invokerPackage}}.Configuration;
import {{invokerPackage}}.Pair;

Expand Down Expand Up @@ -61,6 +62,35 @@ public class {{classname}} {
@Deprecated
{{/isDeprecated}}
public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException {
{{#returnType}}
return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}).getData();
{{/returnType}}{{^returnType}}
{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
{{/returnType}}
}

/**
* {{summary}}
* {{notes}}
{{#allParams}}
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
{{/allParams}}
{{#returnType}}
* @return ApiResponse&lt;{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}&gt;
{{/returnType}}
* @throws ApiException if fails to make API call
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
{{#externalDocs}}
* {{description}}
* @see <a href="{{url}}">{{summary}} Documentation</a>
{{/externalDocs}}
*/
{{#isDeprecated}}
@Deprecated
{{/isDeprecated}}
public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException {
Object {{localVariablePrefix}}localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
{{#allParams}}{{#required}}
// verify the required parameter '{{paramName}}' is set
Expand Down Expand Up @@ -105,7 +135,7 @@ public class {{classname}} {
GenericType<{{{returnType}}}> {{localVariablePrefix}}localVarReturnType = new GenericType<{{{returnType}}}>() {};
return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccept, {{localVariablePrefix}}localVarContentType, {{localVariablePrefix}}localVarAuthNames, {{localVariablePrefix}}localVarReturnType);
{{/returnType}}{{^returnType}}
{{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccept, {{localVariablePrefix}}localVarContentType, {{localVariablePrefix}}localVarAuthNames, null);
return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccept, {{localVariablePrefix}}localVarContentType, {{localVariablePrefix}}localVarAuthNames, null);
{{/returnType}}
}
{{/operation}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ public class ApiClient {

protected Map<String, Authentication> authentications;

protected int statusCode;
protected Map<String, List<String>> responseHeaders;

protected DateFormat dateFormat;

public ApiClient() {
Expand Down Expand Up @@ -114,22 +111,6 @@ public ApiClient setBasePath(String basePath) {
return this;
}

/**
* Gets the status code of the previous request
* @return Status code
*/
public int getStatusCode() {
return statusCode;
}

/**
* Gets the response headers of the previous request
* @return Response headers
*/
public Map<String, List<String>> getResponseHeaders() {
return responseHeaders;
}

/**
* Get authentications (key: authentication name, value: authentication).
* @return Map of authentication object
Expand Down Expand Up @@ -658,7 +639,7 @@ public File prepareDownloadFile(Response response) throws IOException {
* @return The response body in type of string
* @throws ApiException API exception
*/
public <T> T invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
public <T> ApiResponse<T> invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType) throws ApiException {
updateParamsForAuth(authNames, queryParams, headerParams);

// Not using `.target(this.basePath).path(path)` below,
Expand Down Expand Up @@ -713,16 +694,16 @@ public <T> T invokeAPI(String path, String method, List<Pair> queryParams, Objec
throw new ApiException(500, "unknown method type " + method);
}

statusCode = response.getStatusInfo().getStatusCode();
responseHeaders = buildResponseHeaders(response);
int statusCode = response.getStatusInfo().getStatusCode();
Map<String, List<String>> responseHeaders = buildResponseHeaders(response);

if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) {
return null;
return new ApiResponse<>(statusCode, responseHeaders);
} else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) {
if (returnType == null)
return null;
return new ApiResponse<>(statusCode, responseHeaders);
else
return deserialize(response, returnType);
return new ApiResponse<>(statusCode, responseHeaders, deserialize(response, returnType));
} else {
String message = "error";
String respBody = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Swagger Petstore
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
*
* OpenAPI spec version: 1.0.0
* Contact: [email protected]
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/


package io.swagger.client;

import java.util.List;
import java.util.Map;

/**
* API response returned by API call.
*
* @param <T> The type of data that is deserialized from response body
*/
public class ApiResponse<T> {
private final int statusCode;
private final Map<String, List<String>> headers;
private final T data;

/**
* @param statusCode The status code of HTTP response
* @param headers The headers of HTTP response
*/
public ApiResponse(int statusCode, Map<String, List<String>> headers) {
this(statusCode, headers, null);
}

/**
* @param statusCode The status code of HTTP response
* @param headers The headers of HTTP response
* @param data The object deserialized from response bod
*/
public ApiResponse(int statusCode, Map<String, List<String>> headers, T data) {
this.statusCode = statusCode;
this.headers = headers;
this.data = data;
}

public int getStatusCode() {
return statusCode;
}

public Map<String, List<String>> getHeaders() {
return headers;
}

public T getData() {
return data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.swagger.client.ApiException;
import io.swagger.client.ApiClient;
import io.swagger.client.ApiResponse;
import io.swagger.client.Configuration;
import io.swagger.client.Pair;

Expand Down Expand Up @@ -42,6 +43,17 @@ public void setApiClient(ApiClient apiClient) {
* @throws ApiException if fails to make API call
*/
public Client testSpecialTags(Client body) throws ApiException {
return testSpecialTagsWithHttpInfo(body).getData();
}

/**
* To test special tags
* To test special tags
* @param body client model (required)
* @return ApiResponse&lt;Client&gt;
* @throws ApiException if fails to make API call
*/
public ApiResponse<Client> testSpecialTagsWithHttpInfo(Client body) throws ApiException {
Object localVarPostBody = body;

// verify the required parameter 'body' is set
Expand Down
Loading

0 comments on commit cddcda0

Please sign in to comment.