From 72b1749aa54f215b64f5f18b3f6d65ee4d2e9ab9 Mon Sep 17 00:00:00 2001 From: Stian Liknes Date: Wed, 4 Apr 2018 13:18:27 +0200 Subject: [PATCH 1/2] Configuration option to disable HTML escaping when using Gson The default implementation of Gson will escape certain characters by default. This includes the `=` character, which is used in base64 encoding and cause problems when deserializing the value to a base64 encoded string in a service. Adding an option for disabling this feature makes it easier to generate client code with sane defaults. --- .../codegen/languages/AbstractJavaCodegen.java | 11 +++++++++++ .../src/main/resources/Java/JSON.mustache | 6 +++++- .../swagger/codegen/options/JavaOptionsProvider.java | 1 + .../codegen/options/JaxRSServerOptionsProvider.java | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java index 40af7e2111b..aa0c9fff790 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java @@ -53,6 +53,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code public static final String JAVA8_MODE = "java8"; public static final String WITH_XML = "withXml"; public static final String SUPPORT_JAVA6 = "supportJava6"; + public static final String DISABLE_HTML_ESCAPING = "disableHtmlEscaping"; protected String dateLibrary = "threetenbp"; protected boolean java8Mode = false; @@ -85,6 +86,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code protected String apiDocPath = "docs/"; protected String modelDocPath = "docs/"; protected boolean supportJava6= false; + protected boolean disableHtmlEscaping = false; public AbstractJavaCodegen() { super(); @@ -174,6 +176,7 @@ public AbstractJavaCodegen() { java8Mode.setEnum(java8ModeOptions); cliOptions.add(java8Mode); + cliOptions.add(CliOption.newBoolean(DISABLE_HTML_ESCAPING, "Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)")); } @Override @@ -185,6 +188,10 @@ public void processOpts() { } additionalProperties.put(SUPPORT_JAVA6, supportJava6); + if (additionalProperties.containsKey(DISABLE_HTML_ESCAPING)) { + this.setDisableHtmlEscaping(Boolean.valueOf(additionalProperties.get(DISABLE_HTML_ESCAPING).toString())); + } + additionalProperties.put(DISABLE_HTML_ESCAPING, disableHtmlEscaping); if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); @@ -1217,6 +1224,10 @@ public void setJava8Mode(boolean enabled) { this.java8Mode = enabled; } + public void setDisableHtmlEscaping(boolean disabled) { + this.disableHtmlEscaping = disabled; + } + @Override public String escapeQuotationMark(String input) { // remove " to avoid code injection diff --git a/modules/swagger-codegen/src/main/resources/Java/JSON.mustache b/modules/swagger-codegen/src/main/resources/Java/JSON.mustache index 63814a361fc..42580e0ee70 100644 --- a/modules/swagger-codegen/src/main/resources/Java/JSON.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/JSON.mustache @@ -76,7 +76,11 @@ public class JSON { }) {{/parent}} ; - return fireBuilder.createGsonBuilder(); + GsonBuilder builder = fireBuilder.createGsonBuilder(); + {{#disableHtmlEscaping}} + builder.disableHtmlEscaping(); + {{/disableHtmlEscaping}} + return builder; } private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JavaOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JavaOptionsProvider.java index 925fa4c39da..f870adef42f 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JavaOptionsProvider.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JavaOptionsProvider.java @@ -71,6 +71,7 @@ public JavaOptionsProvider() { .put(JavaClientCodegen.JAVA8_MODE, JAVA8_MODE_VALUE) .put(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING, "true") .put(JavaClientCodegen.DATE_LIBRARY, "joda") + .put(JavaClientCodegen.DISABLE_HTML_ESCAPING, "false") .put("hideGenerationTimestamp", "true") .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) //.put("supportJava6", "true") diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JaxRSServerOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JaxRSServerOptionsProvider.java index 9b541833fbe..a36534cf083 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JaxRSServerOptionsProvider.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/JaxRSServerOptionsProvider.java @@ -89,6 +89,7 @@ public Map createOptions() { .put(JavaClientCodegen.WITH_XML, WITH_XML_VALUE) //.put(JavaClientCodegen.DATE_LIBRARY, "joda") .put("hideGenerationTimestamp", "true") + .put(JavaClientCodegen.DISABLE_HTML_ESCAPING, "false") .put(JavaCXFServerCodegen.USE_BEANVALIDATION, USE_BEANVALIDATION) .put("serverPort", "2345") .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) From 282f3593124852409c07b5a37cd966db6e48633e Mon Sep 17 00:00:00 2001 From: Stian Liknes Date: Wed, 4 Apr 2018 13:30:00 +0200 Subject: [PATCH 2/2] Update PetStore sample --- .../java/okhttp-gson/docs/DefaultApi.md | 53 +++++ .../java/okhttp-gson/docs/EnumTest.md | 10 + .../src/main/java/io/swagger/client/JSON.java | 3 +- .../io/swagger/client/api/DefaultApi.java | 186 ++++++++++++++++++ .../io/swagger/client/model/EnumTest.java | 74 ++++++- .../io/swagger/client/api/DefaultApiTest.java | 52 +++++ 6 files changed, 376 insertions(+), 2 deletions(-) create mode 100644 samples/client/petstore/java/okhttp-gson/docs/DefaultApi.md create mode 100644 samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/api/DefaultApi.java create mode 100644 samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/DefaultApiTest.java diff --git a/samples/client/petstore/java/okhttp-gson/docs/DefaultApi.md b/samples/client/petstore/java/okhttp-gson/docs/DefaultApi.md new file mode 100644 index 00000000000..40a52345b6a --- /dev/null +++ b/samples/client/petstore/java/okhttp-gson/docs/DefaultApi.md @@ -0,0 +1,53 @@ +# DefaultApi + +All URIs are relative to *http://petstore.swagger.io:80/v2* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**testBodyWithQueryParams**](DefaultApi.md#testBodyWithQueryParams) | **PUT** /fake/body-with-query-params | + + + +# **testBodyWithQueryParams** +> testBodyWithQueryParams(body, query) + + + +### Example +```java +// Import classes: +//import io.swagger.client.ApiException; +//import io.swagger.client.api.DefaultApi; + + +DefaultApi apiInstance = new DefaultApi(); +User body = new User(); // User | +String query = "query_example"; // String | +try { + apiInstance.testBodyWithQueryParams(body, query); +} catch (ApiException e) { + System.err.println("Exception when calling DefaultApi#testBodyWithQueryParams"); + e.printStackTrace(); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**User**](User.md)| | + **query** | **String**| | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: Not defined + diff --git a/samples/client/petstore/java/okhttp-gson/docs/EnumTest.md b/samples/client/petstore/java/okhttp-gson/docs/EnumTest.md index 08fee344882..ca048bcc515 100644 --- a/samples/client/petstore/java/okhttp-gson/docs/EnumTest.md +++ b/samples/client/petstore/java/okhttp-gson/docs/EnumTest.md @@ -5,6 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **enumString** | [**EnumStringEnum**](#EnumStringEnum) | | [optional] +**enumStringRequired** | [**EnumStringRequiredEnum**](#EnumStringRequiredEnum) | | **enumInteger** | [**EnumIntegerEnum**](#EnumIntegerEnum) | | [optional] **enumNumber** | [**EnumNumberEnum**](#EnumNumberEnum) | | [optional] **outerEnum** | [**OuterEnum**](OuterEnum.md) | | [optional] @@ -19,6 +20,15 @@ LOWER | "lower" EMPTY | "" + +## Enum: EnumStringRequiredEnum +Name | Value +---- | ----- +UPPER | "UPPER" +LOWER | "lower" +EMPTY | "" + + ## Enum: EnumIntegerEnum Name | Value diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java index 15ce43f658a..62b5dae6d0b 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java @@ -64,7 +64,8 @@ public Class getClassForElement(JsonElement readElement) { } }) ; - return fireBuilder.createGsonBuilder(); + GsonBuilder builder = fireBuilder.createGsonBuilder(); + return builder; } private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/api/DefaultApi.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/api/DefaultApi.java new file mode 100644 index 00000000000..42874bd56b2 --- /dev/null +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/api/DefaultApi.java @@ -0,0 +1,186 @@ +/* + * 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: apiteam@swagger.io + * + * 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.api; + +import io.swagger.client.ApiCallback; +import io.swagger.client.ApiClient; +import io.swagger.client.ApiException; +import io.swagger.client.ApiResponse; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.ProgressRequestBody; +import io.swagger.client.ProgressResponseBody; + +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; + + +import io.swagger.client.model.User; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DefaultApi { + private ApiClient apiClient; + + public DefaultApi() { + this(Configuration.getDefaultApiClient()); + } + + public DefaultApi(ApiClient apiClient) { + this.apiClient = apiClient; + } + + public ApiClient getApiClient() { + return apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /** + * Build call for testBodyWithQueryParams + * @param body (required) + * @param query (required) + * @param progressListener Progress listener + * @param progressRequestListener Progress request listener + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + */ + public com.squareup.okhttp.Call testBodyWithQueryParamsCall(User body, String query, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Object localVarPostBody = body; + + // create path and map variables + String localVarPath = "/fake/body-with-query-params"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + if (query != null) + localVarQueryParams.addAll(apiClient.parameterToPair("query", query)); + + Map localVarHeaderParams = new HashMap(); + + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) localVarHeaderParams.put("Accept", localVarAccept); + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + localVarHeaderParams.put("Content-Type", localVarContentType); + + if(progressListener != null) { + apiClient.getHttpClient().networkInterceptors().add(new com.squareup.okhttp.Interceptor() { + @Override + public com.squareup.okhttp.Response intercept(com.squareup.okhttp.Interceptor.Chain chain) throws IOException { + com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }); + } + + String[] localVarAuthNames = new String[] { }; + return apiClient.buildCall(localVarPath, "PUT", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAuthNames, progressRequestListener); + } + + @SuppressWarnings("rawtypes") + private com.squareup.okhttp.Call testBodyWithQueryParamsValidateBeforeCall(User body, String query, final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + + // verify the required parameter 'body' is set + if (body == null) { + throw new ApiException("Missing the required parameter 'body' when calling testBodyWithQueryParams(Async)"); + } + + // verify the required parameter 'query' is set + if (query == null) { + throw new ApiException("Missing the required parameter 'query' when calling testBodyWithQueryParams(Async)"); + } + + + com.squareup.okhttp.Call call = testBodyWithQueryParamsCall(body, query, progressListener, progressRequestListener); + return call; + + } + + /** + * + * + * @param body (required) + * @param query (required) + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public void testBodyWithQueryParams(User body, String query) throws ApiException { + testBodyWithQueryParamsWithHttpInfo(body, query); + } + + /** + * + * + * @param body (required) + * @param query (required) + * @return ApiResponse<Void> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + */ + public ApiResponse testBodyWithQueryParamsWithHttpInfo(User body, String query) throws ApiException { + com.squareup.okhttp.Call call = testBodyWithQueryParamsValidateBeforeCall(body, query, null, null); + return apiClient.execute(call); + } + + /** + * (asynchronously) + * + * @param body (required) + * @param query (required) + * @param callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + */ + public com.squareup.okhttp.Call testBodyWithQueryParamsAsync(User body, String query, final ApiCallback callback) throws ApiException { + + ProgressResponseBody.ProgressListener progressListener = null; + ProgressRequestBody.ProgressRequestListener progressRequestListener = null; + + if (callback != null) { + progressListener = new ProgressResponseBody.ProgressListener() { + @Override + public void update(long bytesRead, long contentLength, boolean done) { + callback.onDownloadProgress(bytesRead, contentLength, done); + } + }; + + progressRequestListener = new ProgressRequestBody.ProgressRequestListener() { + @Override + public void onRequestProgress(long bytesWritten, long contentLength, boolean done) { + callback.onUploadProgress(bytesWritten, contentLength, done); + } + }; + } + + com.squareup.okhttp.Call call = testBodyWithQueryParamsValidateBeforeCall(body, query, progressListener, progressRequestListener); + apiClient.executeAsync(call, callback); + return call; + } +} diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/model/EnumTest.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/model/EnumTest.java index a572c0d6b5b..7a1b9c32152 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/model/EnumTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/model/EnumTest.java @@ -82,6 +82,58 @@ public EnumStringEnum read(final JsonReader jsonReader) throws IOException { @SerializedName("enum_string") private EnumStringEnum enumString = null; + /** + * Gets or Sets enumStringRequired + */ + @JsonAdapter(EnumStringRequiredEnum.Adapter.class) + public enum EnumStringRequiredEnum { + UPPER("UPPER"), + + LOWER("lower"), + + EMPTY(""); + + private String value; + + EnumStringRequiredEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static EnumStringRequiredEnum fromValue(String text) { + for (EnumStringRequiredEnum b : EnumStringRequiredEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + public static class Adapter extends TypeAdapter { + @Override + public void write(final JsonWriter jsonWriter, final EnumStringRequiredEnum enumeration) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public EnumStringRequiredEnum read(final JsonReader jsonReader) throws IOException { + String value = jsonReader.nextString(); + return EnumStringRequiredEnum.fromValue(String.valueOf(value)); + } + } + } + + @SerializedName("enum_string_required") + private EnumStringRequiredEnum enumStringRequired = null; + /** * Gets or Sets enumInteger */ @@ -203,6 +255,24 @@ public void setEnumString(EnumStringEnum enumString) { this.enumString = enumString; } + public EnumTest enumStringRequired(EnumStringRequiredEnum enumStringRequired) { + this.enumStringRequired = enumStringRequired; + return this; + } + + /** + * Get enumStringRequired + * @return enumStringRequired + **/ + @ApiModelProperty(required = true, value = "") + public EnumStringRequiredEnum getEnumStringRequired() { + return enumStringRequired; + } + + public void setEnumStringRequired(EnumStringRequiredEnum enumStringRequired) { + this.enumStringRequired = enumStringRequired; + } + public EnumTest enumInteger(EnumIntegerEnum enumInteger) { this.enumInteger = enumInteger; return this; @@ -268,6 +338,7 @@ public boolean equals(java.lang.Object o) { } EnumTest enumTest = (EnumTest) o; return Objects.equals(this.enumString, enumTest.enumString) && + Objects.equals(this.enumStringRequired, enumTest.enumStringRequired) && Objects.equals(this.enumInteger, enumTest.enumInteger) && Objects.equals(this.enumNumber, enumTest.enumNumber) && Objects.equals(this.outerEnum, enumTest.outerEnum); @@ -275,7 +346,7 @@ public boolean equals(java.lang.Object o) { @Override public int hashCode() { - return Objects.hash(enumString, enumInteger, enumNumber, outerEnum); + return Objects.hash(enumString, enumStringRequired, enumInteger, enumNumber, outerEnum); } @@ -285,6 +356,7 @@ public String toString() { sb.append("class EnumTest {\n"); sb.append(" enumString: ").append(toIndentedString(enumString)).append("\n"); + sb.append(" enumStringRequired: ").append(toIndentedString(enumStringRequired)).append("\n"); sb.append(" enumInteger: ").append(toIndentedString(enumInteger)).append("\n"); sb.append(" enumNumber: ").append(toIndentedString(enumNumber)).append("\n"); sb.append(" outerEnum: ").append(toIndentedString(outerEnum)).append("\n"); diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/DefaultApiTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/DefaultApiTest.java new file mode 100644 index 00000000000..0e36d450e44 --- /dev/null +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/DefaultApiTest.java @@ -0,0 +1,52 @@ +/* + * 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: apiteam@swagger.io + * + * 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.api; + +import io.swagger.client.ApiException; +import io.swagger.client.model.User; +import org.junit.Test; +import org.junit.Ignore; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * API tests for DefaultApi + */ +@Ignore +public class DefaultApiTest { + + private final DefaultApi api = new DefaultApi(); + + + /** + * + * + * + * + * @throws ApiException + * if the Api call fails + */ + @Test + public void testBodyWithQueryParamsTest() throws ApiException { + User body = null; + String query = null; + api.testBodyWithQueryParams(body, query); + + // TODO: test validations + } + +}