[java][okhttp-gson-next-gen] fix serialization, add tests (#11057)

* fix serialization, add tests

* add new files
This commit is contained in:
William Cheng 2021-12-07 16:22:46 +08:00 committed by GitHub
parent 000a18d3b9
commit 192126be6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 347 additions and 6 deletions

View File

@ -60,6 +60,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
if (value.getActualInstance() instanceof {{.}}) {
JsonObject obj = adapter{{.}}.toJsonTree(({{.}})value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
{{/anyOf}}

View File

@ -60,6 +60,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
if (value.getActualInstance() instanceof {{.}}) {
JsonObject obj = adapter{{.}}.toJsonTree(({{.}})value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
{{/oneOf}}

View File

@ -1888,6 +1888,11 @@ components:
type: string
pattern: /^[A-Z\s]*$/i
nullable: true
pineapple:
type: object
properties:
origin:
type: string
banana:
type: object
properties:
@ -1950,6 +1955,7 @@ components:
color:
type: string
anyOf:
- $ref: '#/components/schemas/pineapple'
- $ref: '#/components/schemas/apple'
- $ref: '#/components/schemas/banana'
additionalProperties: false

View File

@ -66,6 +66,7 @@ docs/ParentPet.md
docs/Pet.md
docs/PetApi.md
docs/Pig.md
docs/Pineapple.md
docs/Quadrilateral.md
docs/QuadrilateralInterface.md
docs/ReadOnlyFirst.md
@ -178,6 +179,7 @@ src/main/java/org/openapitools/client/model/OuterEnumIntegerDefaultValue.java
src/main/java/org/openapitools/client/model/ParentPet.java
src/main/java/org/openapitools/client/model/Pet.java
src/main/java/org/openapitools/client/model/Pig.java
src/main/java/org/openapitools/client/model/Pineapple.java
src/main/java/org/openapitools/client/model/Quadrilateral.java
src/main/java/org/openapitools/client/model/QuadrilateralInterface.java
src/main/java/org/openapitools/client/model/ReadOnlyFirst.java

View File

@ -213,6 +213,7 @@ Class | Method | HTTP request | Description
- [ParentPet](docs/ParentPet.md)
- [Pet](docs/Pet.md)
- [Pig](docs/Pig.md)
- [Pineapple](docs/Pineapple.md)
- [Quadrilateral](docs/Quadrilateral.md)
- [QuadrilateralInterface](docs/QuadrilateralInterface.md)
- [ReadOnlyFirst](docs/ReadOnlyFirst.md)

View File

@ -2053,6 +2053,11 @@ components:
pattern: /^[A-Z\s]*$/i
type: string
type: object
pineapple:
properties:
origin:
type: string
type: object
banana:
properties:
lengthCm:
@ -2113,6 +2118,7 @@ components:
gmFruit:
additionalProperties: false
anyOf:
- $ref: '#/components/schemas/pineapple'
- $ref: '#/components/schemas/apple'
- $ref: '#/components/schemas/banana'
properties:

View File

@ -8,8 +8,8 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**color** | **String** | | [optional]
**cultivar** | **String** | | [optional]
**origin** | **String** | | [optional]
**cultivar** | **String** | | [optional]
**lengthCm** | **BigDecimal** | | [optional]

View File

@ -0,0 +1,13 @@
# Pineapple
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**origin** | **String** | | [optional]

View File

@ -270,6 +270,7 @@ public class JSON {
.registerTypeAdapterFactory(new org.openapitools.client.model.ParentPet.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.Pet.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.Pig.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.Pineapple.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.Quadrilateral.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.QuadrilateralInterface.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ReadOnlyFirst.CustomTypeAdapterFactory())

View File

@ -87,12 +87,14 @@ public class Fruit extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof Apple) {
JsonObject obj = adapterApple.toJsonTree((Apple)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Banana`
if (value.getActualInstance() instanceof Banana) {
JsonObject obj = adapterBanana.toJsonTree((Banana)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: Apple, Banana");

View File

@ -87,12 +87,14 @@ public class FruitReq extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof AppleReq) {
JsonObject obj = adapterAppleReq.toJsonTree((AppleReq)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `BananaReq`
if (value.getActualInstance() instanceof BananaReq) {
JsonObject obj = adapterBananaReq.toJsonTree((BananaReq)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: AppleReq, BananaReq");

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import org.openapitools.client.model.Apple;
import org.openapitools.client.model.Banana;
import org.openapitools.client.model.Pineapple;
import javax.ws.rs.core.GenericType;
@ -74,6 +75,7 @@ public class GmFruit extends AbstractOpenApiSchema {
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
final TypeAdapter<Apple> adapterApple = gson.getDelegateAdapter(this, TypeToken.get(Apple.class));
final TypeAdapter<Banana> adapterBanana = gson.getDelegateAdapter(this, TypeToken.get(Banana.class));
final TypeAdapter<Pineapple> adapterPineapple = gson.getDelegateAdapter(this, TypeToken.get(Pineapple.class));
return (TypeAdapter<T>) new TypeAdapter<GmFruit>() {
@Override
@ -87,15 +89,24 @@ public class GmFruit extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof Apple) {
JsonObject obj = adapterApple.toJsonTree((Apple)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Banana`
if (value.getActualInstance() instanceof Banana) {
JsonObject obj = adapterBanana.toJsonTree((Banana)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match anyOf schemas: Apple, Banana");
// check if the actual instance is of the type `Pineapple`
if (value.getActualInstance() instanceof Pineapple) {
JsonObject obj = adapterPineapple.toJsonTree((Pineapple)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match anyOf schemas: Apple, Banana, Pineapple");
}
@Override
@ -126,6 +137,18 @@ public class GmFruit extends AbstractOpenApiSchema {
log.log(Level.FINER, "Input data does not match schema 'Banana'", e);
}
// deserialize Pineapple
try {
deserialized = gson.fromJson(in, Pineapple.class);
log.log(Level.FINER, "Input data matches schema 'Pineapple'");
GmFruit ret = new GmFruit();
ret.setActualInstance(deserialized);
return ret;
} catch (Exception e) {
// deserialization failed, continue
log.log(Level.FINER, "Input data does not match schema 'Pineapple'", e);
}
throw new IOException("Failed deserialization for GmFruit: no match found.");
}
}.nullSafe();
@ -149,11 +172,18 @@ public class GmFruit extends AbstractOpenApiSchema {
setActualInstance(o);
}
public GmFruit(Pineapple o) {
super("anyOf", Boolean.FALSE);
setActualInstance(o);
}
static {
schemas.put("Apple", new GenericType<Apple>() {
});
schemas.put("Banana", new GenericType<Banana>() {
});
schemas.put("Pineapple", new GenericType<Pineapple>() {
});
}
@Override
@ -164,7 +194,7 @@ public class GmFruit extends AbstractOpenApiSchema {
/**
* Set the instance that matches the anyOf child schema, check
* the instance parameter is valid against the anyOf child schemas:
* Apple, Banana
* Apple, Banana, Pineapple
*
* It could be an instance of the 'anyOf' schemas.
* The anyOf child schemas may themselves be a composed schema (allOf, anyOf, anyOf).
@ -181,14 +211,19 @@ public class GmFruit extends AbstractOpenApiSchema {
return;
}
throw new RuntimeException("Invalid instance type. Must be Apple, Banana");
if (instance instanceof Pineapple) {
super.setActualInstance(instance);
return;
}
throw new RuntimeException("Invalid instance type. Must be Apple, Banana, Pineapple");
}
/**
* Get the actual instance, which can be the following:
* Apple, Banana
* Apple, Banana, Pineapple
*
* @return The actual instance (Apple, Banana)
* @return The actual instance (Apple, Banana, Pineapple)
*/
@Override
public Object getActualInstance() {
@ -217,5 +252,16 @@ public class GmFruit extends AbstractOpenApiSchema {
return (Banana)super.getActualInstance();
}
/**
* Get the actual instance of `Pineapple`. If the actual instance is not `Pineapple`,
* the ClassCastException will be thrown.
*
* @return The actual instance of `Pineapple`
* @throws ClassCastException if the instance is not `Pineapple`
*/
public Pineapple getPineapple() throws ClassCastException {
return (Pineapple)super.getActualInstance();
}
}

View File

@ -88,18 +88,21 @@ public class Mammal extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof Pig) {
JsonObject obj = adapterPig.toJsonTree((Pig)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Whale`
if (value.getActualInstance() instanceof Whale) {
JsonObject obj = adapterWhale.toJsonTree((Whale)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Zebra`
if (value.getActualInstance() instanceof Zebra) {
JsonObject obj = adapterZebra.toJsonTree((Zebra)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: Pig, Whale, Zebra");

View File

@ -86,12 +86,14 @@ public class NullableShape extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof Quadrilateral) {
JsonObject obj = adapterQuadrilateral.toJsonTree((Quadrilateral)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Triangle`
if (value.getActualInstance() instanceof Triangle) {
JsonObject obj = adapterTriangle.toJsonTree((Triangle)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: Quadrilateral, Triangle");

View File

@ -86,12 +86,14 @@ public class Pig extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof BasquePig) {
JsonObject obj = adapterBasquePig.toJsonTree((BasquePig)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `DanishPig`
if (value.getActualInstance() instanceof DanishPig) {
JsonObject obj = adapterDanishPig.toJsonTree((DanishPig)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: BasquePig, DanishPig");

View File

@ -0,0 +1,162 @@
/*
* OpenAPI 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: \" \\
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.model;
import java.util.Objects;
import java.util.Arrays;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Pineapple
*/
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class Pineapple {
public static final String SERIALIZED_NAME_ORIGIN = "origin";
@SerializedName(SERIALIZED_NAME_ORIGIN)
private String origin;
public Pineapple() {
}
public Pineapple origin(String origin) {
this.origin = origin;
return this;
}
/**
* Get origin
* @return origin
**/
@javax.annotation.Nullable
@ApiModelProperty(value = "")
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Pineapple pineapple = (Pineapple) o;
return Objects.equals(this.origin, pineapple.origin);
}
@Override
public int hashCode() {
return Objects.hash(origin);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class Pineapple {\n");
sb.append(" origin: ").append(toIndentedString(origin)).append("\n");
sb.append("}");
return sb.toString();
}
/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
public static HashSet<String> openapiFields;
public static HashSet<String> openapiRequiredFields;
static {
// a set of all properties/fields (JSON key names)
openapiFields = new HashSet<String>();
openapiFields.add("origin");
// a set of required properties/fields (JSON key names)
openapiRequiredFields = new HashSet<String>();
}
public static class CustomTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!Pineapple.class.isAssignableFrom(type.getRawType())) {
return null; // this class only serializes 'Pineapple' and its subtypes
}
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
final TypeAdapter<Pineapple> thisAdapter
= gson.getDelegateAdapter(this, TypeToken.get(Pineapple.class));
return (TypeAdapter<T>) new TypeAdapter<Pineapple>() {
@Override
public void write(JsonWriter out, Pineapple value) throws IOException {
JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject();
elementAdapter.write(out, obj);
}
@Override
public Pineapple read(JsonReader in) throws IOException {
JsonObject obj = elementAdapter.read(in).getAsJsonObject();
Set<Entry<String, JsonElement>> entries = obj.entrySet();//will return members of your object
// check to see if the JSON string contains additional fields
for (Entry<String, JsonElement> entry: entries) {
if (!Pineapple.openapiFields.contains(entry.getKey())) {
throw new IllegalArgumentException("The field `" + entry.getKey() + "` in the JSON string is not defined in the `Pineapple` properties");
}
}
return thisAdapter.fromJsonTree(obj);
}
}.nullSafe();
}
}
}

View File

@ -86,12 +86,14 @@ public class Quadrilateral extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof ComplexQuadrilateral) {
JsonObject obj = adapterComplexQuadrilateral.toJsonTree((ComplexQuadrilateral)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `SimpleQuadrilateral`
if (value.getActualInstance() instanceof SimpleQuadrilateral) {
JsonObject obj = adapterSimpleQuadrilateral.toJsonTree((SimpleQuadrilateral)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: ComplexQuadrilateral, SimpleQuadrilateral");

View File

@ -86,12 +86,14 @@ public class Shape extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof Quadrilateral) {
JsonObject obj = adapterQuadrilateral.toJsonTree((Quadrilateral)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Triangle`
if (value.getActualInstance() instanceof Triangle) {
JsonObject obj = adapterTriangle.toJsonTree((Triangle)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: Quadrilateral, Triangle");

View File

@ -86,12 +86,14 @@ public class ShapeOrNull extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof Quadrilateral) {
JsonObject obj = adapterQuadrilateral.toJsonTree((Quadrilateral)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `Triangle`
if (value.getActualInstance() instanceof Triangle) {
JsonObject obj = adapterTriangle.toJsonTree((Triangle)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: Quadrilateral, Triangle");

View File

@ -88,18 +88,21 @@ public class Triangle extends AbstractOpenApiSchema {
if (value.getActualInstance() instanceof EquilateralTriangle) {
JsonObject obj = adapterEquilateralTriangle.toJsonTree((EquilateralTriangle)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `IsoscelesTriangle`
if (value.getActualInstance() instanceof IsoscelesTriangle) {
JsonObject obj = adapterIsoscelesTriangle.toJsonTree((IsoscelesTriangle)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
// check if the actual instance is of the type `ScaleneTriangle`
if (value.getActualInstance() instanceof ScaleneTriangle) {
JsonObject obj = adapterScaleneTriangle.toJsonTree((ScaleneTriangle)value.getActualInstance()).getAsJsonObject();
elementAdapter.write(out, obj);
return;
}
throw new IOException("Failed to deserialize as the type doesn't match oneOf schemas: EquilateralTriangle, IsoscelesTriangle, ScaleneTriangle");

View File

@ -286,6 +286,36 @@ public class JSONTest {
return offset;
}
/**
* Validate an anyOf schema can be deserialized into the expected class.
* The anyOf schema does not have a discriminator.
*/
@Test
public void testAnyOfSchemaWithoutDiscriminator() throws Exception {
{
String str = "{ \"cultivar\": \"golden delicious\", \"origin\": \"japan\" }";
String str2 = "{ \"origin_typo\": \"japan\" }";
// make sure deserialization works for pojo object
Apple a = json.getGson().fromJson(str, Apple.class);
assertEquals(a.getCultivar(), "golden delicious");
assertEquals(a.getOrigin(), "japan");
GmFruit o = json.getGson().fromJson(str, GmFruit.class);
assertTrue(o.getActualInstance() instanceof Apple);
Apple inst = (Apple) o.getActualInstance();
assertEquals(inst.getCultivar(), "golden delicious");
assertEquals(inst.getOrigin(), "japan");
assertEquals(json.getGson().toJson(inst), "{\"cultivar\":\"golden delicious\",\"origin\":\"japan\"}");
assertEquals(json.getGson().toJson(o), "{\"cultivar\":\"golden delicious\",\"origin\":\"japan\"}");
// no match
Exception exception = assertThrows(com.google.gson.JsonSyntaxException.class, () -> {
GmFruit o2 = json.getGson().fromJson(str2, GmFruit.class);
});
}
}
/**
* Validate a oneOf schema can be deserialized into the expected class.
* The oneOf schema does not have a discriminator.
@ -308,6 +338,7 @@ public class JSONTest {
assertEquals(inst.getCultivar(), "golden delicious");
assertEquals(inst.getMealy(), false);
assertEquals(json.getGson().toJson(inst), "{\"cultivar\":\"golden delicious\",\"mealy\":false}");
assertEquals(json.getGson().toJson(o), "{\"cultivar\":\"golden delicious\",\"mealy\":false}");
AppleReq inst2 = o.getAppleReq();
assertEquals(inst2.getCultivar(), "golden delicious");

View File

@ -0,0 +1,51 @@
/*
* OpenAPI 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: \" \\
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.model;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
/**
* Model tests for Pineapple
*/
public class PineappleTest {
private final Pineapple model = new Pineapple();
/**
* Model tests for Pineapple
*/
@Test
public void testPineapple() {
// TODO: test Pineapple
}
/**
* Test the property 'origin'
*/
@Test
public void originTest() {
// TODO: test origin
}
}