Skip to content

Commit

Permalink
Issue 4824 fix gson deserialize format byte (#7473)
Browse files Browse the repository at this point in the history
* Build sample prior to code changes so differences are easier to decipher

* Add byte array type adapter for okhttp-gson (java8 only)

* Unit revealed that Gson (or GsonFire) defaults to escape = (equal sign) out of base64 string.  Add disableHtmlEscaping() to gsonbuilder.

* Update specs and samples to include format=byte and include junit test of byte array serialization and deserialization.

* Implement recommendations by @cbornet including: Use okio.ByteString for base64 conversions instead of java 8 lib since the okhttp-gson client already includes okio. Remove setting to disableHtmlEscaping. Rename LocalByteArrayAdapter to ByteArrayAdapter.

* Update spec and sample for java okhttp-gson library client

* Undo addition of profilePhoto property.  A format byte property is already available under the format_test definition.

* Put previously deleted tests back. Modified testFindPetsByTags() to verify exception since the server now returns a 500 for this request.

* Update test to pass when run against docker containerized server swaggerapi/petstore (heads up, this test fails if calling out to the internet published version of http://petstore.swagger.io)
  • Loading branch information
benrobot authored and wing328 committed Jan 26, 2018
1 parent 2d89851 commit 47111b3
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 248 deletions.
2 changes: 1 addition & 1 deletion bin/windows/java-petstore-okhttp-gson.bat
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ If Not Exist %executable% (
)

REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
set ags=generate -i modules\swagger-codegen\src\test\resources\2_0\petstore-with-fake-endpoints-models-for-testing.yaml -l java -o samples\client\petstore\java --library=okhttp-gson -DdateLibrary=joda -DhideGenerationTimestamp=true
set ags=generate -t modules\swagger-codegen\src\main\resources\Java\libraries\okhttp-gson -i modules\swagger-codegen\src\test\resources\2_0\petstore-with-fake-endpoints-models-for-testing.yaml -l java -c bin\java-petstore-okhttp-gson.json -o samples\client\petstore\java\okhttp-gson -DhideGenerationTimestamp=true

java %JAVA_OPTS% -jar %executable% %ags%
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.threeten.bp.format.DateTimeFormatter;
{{/threetenbp}}

import {{modelPackage}}.*;
import okio.ByteString;

import java.io.IOException;
import java.io.StringReader;
Expand Down Expand Up @@ -55,6 +56,7 @@ public class JSON {
private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter();
private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter();
{{/jsr310}}
private ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter();

public static GsonBuilder createGson() {
GsonFireBuilder fireBuilder = new GsonFireBuilder()
Expand Down Expand Up @@ -105,6 +107,7 @@ public class JSON {
.registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter)
.registerTypeAdapter(LocalDate.class, localDateTypeAdapter)
{{/jsr310}}
.registerTypeAdapter(byte[].class, byteArrayAdapter)
.create();
}

Expand Down Expand Up @@ -171,6 +174,34 @@ public class JSON {
}
}

/**
* Gson TypeAdapter for Byte Array type
*/
public class ByteArrayAdapter extends TypeAdapter<byte[]> {
@Override
public void write(JsonWriter out, byte[] value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(ByteString.of(value).base64());
}
}

@Override
public byte[] read(JsonReader in) throws IOException {
switch (in.peek()) {
case NULL:
in.nextNull();
return null;
default:
String bytesAsBase64 = in.nextString();
ByteString byteString = ByteString.decodeBase64(bytesAsBase64);
return byteString.toByteArray();
}
}
}

{{#joda}}
/**
* Gson TypeAdapter for Joda DateTime type
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.4.0-SNAPSHOT
2.4.0-SNAPSHOT
150 changes: 81 additions & 69 deletions samples/client/petstore/java/okhttp-gson/README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
# swagger-petstore-okhttp-gson

Swagger Petstore
- API version: 1.0.0

This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\


*Automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen)*


## Requirements

Building the API client library requires [Maven](https://maven.apache.org/) to be installed.
Building the API client library requires:
1. Java 1.7+
2. Maven/Gradle

## Installation

To install the API client library to your local Maven repository, simply execute:

```shell
mvn install
mvn clean install
```

To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:

```shell
mvn deploy
mvn clean deploy
```

Refer to the [official documentation](https://maven.apache.org/plugins/maven-deploy-plugin/usage.html) for more information.
Refer to the [OSSRH Guide](http://central.sonatype.org/pages/ossrh-guide.html) for more information.

### Maven users

Add this dependency to your project's POM:

```xml
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-petstore-okhttp-gson</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
<groupId>io.swagger</groupId>
<artifactId>swagger-petstore-okhttp-gson</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
```

Expand All @@ -45,12 +56,14 @@ compile "io.swagger:swagger-petstore-okhttp-gson:1.0.0"

At first generate the JAR by executing:

mvn package
```shell
mvn clean package
```

Then manually install the following JARs:

* target/swagger-petstore-okhttp-gson-1.0.0.jar
* target/lib/*.jar
* `target/swagger-petstore-okhttp-gson-1.0.0.jar`
* `target/lib/*.jar`

## Getting Started

Expand All @@ -61,30 +74,22 @@ Please follow the [installation](#installation) instruction and execute the foll
import io.swagger.client.*;
import io.swagger.client.auth.*;
import io.swagger.client.model.*;
import io.swagger.client.api.PetApi;
import io.swagger.client.api.AnotherFakeApi;

import java.io.File;
import java.util.*;

public class PetApiExample {
public class AnotherFakeApiExample {

public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();

// Configure OAuth2 access token for authorization: petstore_auth
OAuth petstore_auth = (OAuth) defaultClient.getAuthentication("petstore_auth");
petstore_auth.setAccessToken("YOUR ACCESS TOKEN");



PetApi apiInstance = new PetApi();

Pet body = new Pet(); // Pet | Pet object that needs to be added to the store

AnotherFakeApi apiInstance = new AnotherFakeApi();
Client body = new Client(); // Client | client model
try {
apiInstance.addPet(body);
Client result = apiInstance.testSpecialTags(body);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling PetApi#addPet");
System.err.println("Exception when calling AnotherFakeApi#testSpecialTags");
e.printStackTrace();
}
}
Expand All @@ -94,26 +99,32 @@ public class PetApiExample {

## Documentation for API Endpoints

All URIs are relative to *http://petstore.swagger.io/v2*
All URIs are relative to *http://petstore.swagger.io:80/v2*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*AnotherFakeApi* | [**testSpecialTags**](docs/AnotherFakeApi.md#testSpecialTags) | **PATCH** /another-fake/dummy | To test special tags
*FakeApi* | [**fakeOuterBooleanSerialize**](docs/FakeApi.md#fakeOuterBooleanSerialize) | **POST** /fake/outer/boolean |
*FakeApi* | [**fakeOuterCompositeSerialize**](docs/FakeApi.md#fakeOuterCompositeSerialize) | **POST** /fake/outer/composite |
*FakeApi* | [**fakeOuterNumberSerialize**](docs/FakeApi.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number |
*FakeApi* | [**fakeOuterStringSerialize**](docs/FakeApi.md#fakeOuterStringSerialize) | **POST** /fake/outer/string |
*FakeApi* | [**testClientModel**](docs/FakeApi.md#testClientModel) | **PATCH** /fake | To test \&quot;client\&quot; model
*FakeApi* | [**testEndpointParameters**](docs/FakeApi.md#testEndpointParameters) | **POST** /fake | Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
*FakeApi* | [**testEnumParameters**](docs/FakeApi.md#testEnumParameters) | **GET** /fake | To test enum parameters
*FakeApi* | [**testInlineAdditionalProperties**](docs/FakeApi.md#testInlineAdditionalProperties) | **POST** /fake/inline-additionalProperties | test inline additionalProperties
*FakeApi* | [**testJsonFormData**](docs/FakeApi.md#testJsonFormData) | **GET** /fake/jsonFormData | test json serialization of form data
*FakeClassnameTags123Api* | [**testClassname**](docs/FakeClassnameTags123Api.md#testClassname) | **PATCH** /fake_classname_test | To test class name in snake case
*PetApi* | [**addPet**](docs/PetApi.md#addPet) | **POST** /pet | Add a new pet to the store
*PetApi* | [**addPetUsingByteArray**](docs/PetApi.md#addPetUsingByteArray) | **POST** /pet?testing_byte_array=true | Fake endpoint to test byte array in body parameter for adding a new pet to the store
*PetApi* | [**deletePet**](docs/PetApi.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet
*PetApi* | [**findPetsByStatus**](docs/PetApi.md#findPetsByStatus) | **GET** /pet/findByStatus | Finds Pets by status
*PetApi* | [**findPetsByTags**](docs/PetApi.md#findPetsByTags) | **GET** /pet/findByTags | Finds Pets by tags
*PetApi* | [**getPetById**](docs/PetApi.md#getPetById) | **GET** /pet/{petId} | Find pet by ID
*PetApi* | [**getPetByIdInObject**](docs/PetApi.md#getPetByIdInObject) | **GET** /pet/{petId}?response=inline_arbitrary_object | Fake endpoint to test inline arbitrary object return by &#39;Find pet by ID&#39;
*PetApi* | [**petPetIdtestingByteArraytrueGet**](docs/PetApi.md#petPetIdtestingByteArraytrueGet) | **GET** /pet/{petId}?testing_byte_array=true | Fake endpoint to test byte array return by &#39;Find pet by ID&#39;
*PetApi* | [**updatePet**](docs/PetApi.md#updatePet) | **PUT** /pet | Update an existing pet
*PetApi* | [**updatePetWithForm**](docs/PetApi.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data
*PetApi* | [**uploadFile**](docs/PetApi.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image
*StoreApi* | [**deleteOrder**](docs/StoreApi.md#deleteOrder) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
*StoreApi* | [**findOrdersByStatus**](docs/StoreApi.md#findOrdersByStatus) | **GET** /store/findByStatus | Finds orders by status
*StoreApi* | [**deleteOrder**](docs/StoreApi.md#deleteOrder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID
*StoreApi* | [**getInventory**](docs/StoreApi.md#getInventory) | **GET** /store/inventory | Returns pet inventories by status
*StoreApi* | [**getInventoryInObject**](docs/StoreApi.md#getInventoryInObject) | **GET** /store/inventory?response=arbitrary_object | Fake endpoint to test arbitrary object return by &#39;Get inventory&#39;
*StoreApi* | [**getOrderById**](docs/StoreApi.md#getOrderById) | **GET** /store/order/{orderId} | Find purchase order by ID
*StoreApi* | [**getOrderById**](docs/StoreApi.md#getOrderById) | **GET** /store/order/{order_id} | Find purchase order by ID
*StoreApi* | [**placeOrder**](docs/StoreApi.md#placeOrder) | **POST** /store/order | Place an order for a pet
*UserApi* | [**createUser**](docs/UserApi.md#createUser) | **POST** /user | Create user
*UserApi* | [**createUsersWithArrayInput**](docs/UserApi.md#createUsersWithArrayInput) | **POST** /user/createWithArray | Creates list of users with given input array
Expand All @@ -127,71 +138,72 @@ Class | Method | HTTP request | Description

## Documentation for Models

- [AdditionalPropertiesClass](docs/AdditionalPropertiesClass.md)
- [Animal](docs/Animal.md)
- [Cat](docs/Cat.md)
- [AnimalFarm](docs/AnimalFarm.md)
- [ArrayOfArrayOfNumberOnly](docs/ArrayOfArrayOfNumberOnly.md)
- [ArrayOfNumberOnly](docs/ArrayOfNumberOnly.md)
- [ArrayTest](docs/ArrayTest.md)
- [Capitalization](docs/Capitalization.md)
- [Category](docs/Category.md)
- [Dog](docs/Dog.md)
- [InlineResponse200](docs/InlineResponse200.md)
- [ClassModel](docs/ClassModel.md)
- [Client](docs/Client.md)
- [EnumArrays](docs/EnumArrays.md)
- [EnumClass](docs/EnumClass.md)
- [EnumTest](docs/EnumTest.md)
- [FormatTest](docs/FormatTest.md)
- [HasOnlyReadOnly](docs/HasOnlyReadOnly.md)
- [MapTest](docs/MapTest.md)
- [MixedPropertiesAndAdditionalPropertiesClass](docs/MixedPropertiesAndAdditionalPropertiesClass.md)
- [Model200Response](docs/Model200Response.md)
- [ModelApiResponse](docs/ModelApiResponse.md)
- [ModelReturn](docs/ModelReturn.md)
- [Name](docs/Name.md)
- [NumberOnly](docs/NumberOnly.md)
- [Order](docs/Order.md)
- [OuterComposite](docs/OuterComposite.md)
- [OuterEnum](docs/OuterEnum.md)
- [Pet](docs/Pet.md)
- [ReadOnlyFirst](docs/ReadOnlyFirst.md)
- [SpecialModelName](docs/SpecialModelName.md)
- [Tag](docs/Tag.md)
- [User](docs/User.md)
- [Cat](docs/Cat.md)
- [Dog](docs/Dog.md)


## Documentation for Authorization

Authentication schemes defined for the API:
### petstore_auth

- **Type**: OAuth
- **Flow**: implicit
- **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog
- **Scopes**:
- write:pets: modify pets in your account
- read:pets: read your pets

### test_api_client_id

- **Type**: API key
- **API key parameter name**: x-test_api_client_id
- **Location**: HTTP header

### test_api_client_secret

- **Type**: API key
- **API key parameter name**: x-test_api_client_secret
- **Location**: HTTP header

### api_key

- **Type**: API key
- **API key parameter name**: api_key
- **Location**: HTTP header

### test_http_basic

- **Type**: HTTP basic authentication

### test_api_key_query
### api_key_query

- **Type**: API key
- **API key parameter name**: test_api_key_query
- **API key parameter name**: api_key_query
- **Location**: URL query string

### test_api_key_header
### http_basic_test

- **Type**: API key
- **API key parameter name**: test_api_key_header
- **Location**: HTTP header
- **Type**: HTTP basic authentication

### petstore_auth

- **Type**: OAuth
- **Flow**: implicit
- **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog
- **Scopes**:
- write:pets: modify pets in your account
- read:pets: read your pets


## Recommendation

It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issue.
It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues.

## Author

Expand Down
8 changes: 8 additions & 0 deletions samples/client/petstore/java/okhttp-gson/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ if(hasProperty('target') && target == 'android') {
main = System.getProperty('mainClass')
classpath = sourceSets.main.runtimeClasspath
}

compileJava {
options.encoding = "UTF8"
}

compileTestJava {
options.encoding = "UTF8"
}
}

dependencies {
Expand Down
12 changes: 0 additions & 12 deletions samples/client/petstore/java/okhttp-gson/docs/ApiResponse.md

This file was deleted.

Loading

0 comments on commit 47111b3

Please sign in to comment.