From 5b2ceac93d90b657af125592253bf986bc2b591a Mon Sep 17 00:00:00 2001 From: William Cheng Date: Sun, 6 Aug 2023 13:48:13 +0800 Subject: [PATCH] fix anyOf in handling primitive types in java client (#16264) --- .../okhttp-gson/anyof_model.mustache | 231 ++++++++++--- .../okhttp-gson/oneof_model.mustache | 1 - ...points-models-for-testing-okhttp-gson.yaml | 7 + .../client/model/SimpleOneOf.java | 1 - .../java/okhttp-gson/.openapi-generator/FILES | 2 + .../petstore/java/okhttp-gson/README.md | 1 + .../java/okhttp-gson/api/openapi.yaml | 7 + .../java/okhttp-gson/docs/ScalarAnyOf.md | 13 + .../java/org/openapitools/client/JSON.java | 1 + .../org/openapitools/client/model/Fruit.java | 1 - .../openapitools/client/model/FruitReq.java | 1 - .../openapitools/client/model/GmFruit.java | 77 ++--- .../org/openapitools/client/model/Mammal.java | 1 - .../client/model/NullableShape.java | 1 - .../org/openapitools/client/model/Pig.java | 1 - .../client/model/Quadrilateral.java | 1 - .../org/openapitools/client/model/Scalar.java | 1 - .../client/model/ScalarAnyOf.java | 325 ++++++++++++++++++ .../org/openapitools/client/model/Shape.java | 1 - .../client/model/ShapeOrNull.java | 1 - .../openapitools/client/model/Triangle.java | 1 - .../org/openapitools/client/model/Value.java | 1 - .../org/openapitools/client/JSONTest.java | 35 ++ .../client/model/ScalarAnyOfTest.java | 34 ++ 24 files changed, 650 insertions(+), 96 deletions(-) create mode 100644 samples/client/petstore/java/okhttp-gson/docs/ScalarAnyOf.md create mode 100644 samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ScalarAnyOf.java create mode 100644 samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/model/ScalarAnyOfTest.java diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/anyof_model.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/anyof_model.mustache index 39a942e04a3..fbf4807c73e 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/anyof_model.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/anyof_model.mustache @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import com.google.gson.Gson; @@ -27,6 +28,7 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonArray; import com.google.gson.JsonParseException; import {{invokerPackage}}.JSON; @@ -43,9 +45,18 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im return null; // this class only serializes '{{classname}}' and its subtypes } final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + {{#composedSchemas}} {{#anyOf}} - final TypeAdapter<{{.}}> adapter{{.}} = gson.getDelegateAdapter(this, TypeToken.get({{.}}.class)); + {{^isArray}} + final TypeAdapter<{{{dataType}}}> adapter{{{dataType}}} = gson.getDelegateAdapter(this, TypeToken.get({{{dataType}}}.class)); + {{/isArray}} + {{#isArray}} + + final Type typeInstance = new TypeToken>(){}.getType(); + final TypeAdapter<{{{dataType}}}> adapter{{complexType}}List = (TypeAdapter>) gson.getDelegateAdapter(this, TypeToken.get(typeInstance)); + {{/isArray}} {{/anyOf}} + {{/composedSchemas}} return (TypeAdapter) new TypeAdapter<{{classname}}>() { @Override @@ -55,16 +66,34 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im return; } + {{#composedSchemas}} {{#anyOf}} - // check if the actual instance is of the type `{{.}}` - if (value.getActualInstance() instanceof {{.}}) { - JsonObject obj = adapter{{.}}.toJsonTree(({{.}})value.getActualInstance()).getAsJsonObject(); - elementAdapter.write(out, obj); + // check if the actual instance is of the type `{{{dataType}}}` + if (value.getActualInstance() instanceof {{#isArray}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) { + {{#isPrimitiveType}} + JsonPrimitive primitive = adapter{{{dataType}}}.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonPrimitive(); + elementAdapter.write(out, primitive); + return; + {{/isPrimitiveType}} + {{#isArray}} + List list = (List) value.getActualInstance(); + if(list.get(0) instanceof {{complexType}}) { + JsonArray array = adapter{{{complexType}}}List.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonArray(); + elementAdapter.write(out, array); return; + } + {{/isArray}} + {{^isArray}} + {{^isPrimitiveType}} + JsonElement element = adapter{{{dataType}}}.toJsonTree(({{{dataType}}})value.getActualInstance()); + elementAdapter.write(out, element); + return; + {{/isPrimitiveType}} + {{/isArray}} } - {{/anyOf}} - throw new IOException("Failed to serialize as the type doesn't match anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}"); + {{/composedSchemas}} + throw new IOException("Failed to serialize as the type doesn't match anyOf schemae: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}"); } @Override @@ -72,41 +101,93 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im Object deserialized = null; JsonElement jsonElement = elementAdapter.read(in); - {{#useOneOfDiscriminatorLookup}} - {{#discriminator}} - // use discriminator value for faster anyOf lookup - {{classname}} new{{classname}} = new {{classname}}(); - String discriminatorValue = elementAdapter.read(in).getAsJsonObject().get("{{{propertyBaseName}}}").getAsString(); - switch (discriminatorValue) { - {{#mappedModels}} - case "{{{mappingName}}}": - deserialized = adapter{{modelName}}.fromJsonTree(jsonElement); - new{{classname}}.setActualInstance(deserialized); - return new{{classname}}; - {{/mappedModels}} - default: - log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for {{classname}}. Possible values:{{#mappedModels}} {{{mappingName}}}{{/mappedModels}}", discriminatorValue)); - } + ArrayList errorMessages = new ArrayList<>(); + TypeAdapter actualAdapter = elementAdapter; - {{/discriminator}} - {{/useOneOfDiscriminatorLookup}} + {{#composedSchemas}} {{#anyOf}} + {{^hasVars}} + // deserialize {{{dataType}}} + try { + // validate the JSON object to see if any exception is thrown + {{#isNumber}} + if(!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapter{{{dataType}}}; + {{/isNumber}} + {{^isNumber}} + {{#isPrimitiveType}} + if(!jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapter{{{dataType}}}; + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{^isArray}} + {{{dataType}}}.validateJsonElement(jsonElement); + actualAdapter = adapter{{{dataType}}}; + {{/isArray}} + {{/isPrimitiveType}} + {{/isNumber}} + {{#isArray}} + if (!jsonElement.isJsonArray()) { + throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString())); + } + + JsonArray array = jsonElement.getAsJsonArray(); + // validate array items + for(JsonElement element : array) { + {{#items}} + {{#isNumber}} + if(!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapter{{{dataType}}}; + {{/isNumber}} + {{^isNumber}} + {{#isPrimitiveType}} + if(!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{{dataType}}}.validateJsonElement(element); + {{/isPrimitiveType}} + {{/isNumber}} + {{/items}} + } + actualAdapter = adapter{{{complexType}}}List; + {{/isArray}} + {{classname}} ret = new {{classname}}(); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); + return ret; + } catch (Exception e) { + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema '{{{dataType}}}'", e); + } + {{/hasVars}} + {{#hasVars}} // deserialize {{{.}}} try { // validate the JSON object to see if any exception is thrown {{.}}.validateJsonElement(jsonElement); - log.log(Level.FINER, "Input data matches schema '{{{.}}}'"); + actualAdapter = adapter{{.}}; {{classname}} ret = new {{classname}}(); - ret.setActualInstance(adapter{{.}}.fromJsonTree(jsonElement)); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); return ret; + log.log(Level.FINER, "Input data matches schema '{{{.}}}'"); } catch (Exception e) { // deserialization failed, continue + errorMessages.add(String.format("Deserialization for {{{.}}} failed with `%s`.", e.getMessage())); log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e); } - + {{/hasVars}} {{/anyOf}} + {{/composedSchemas}} - throw new IOException(String.format("Failed deserialization for {{classname}}: no class matched. JSON: %s", jsonElement.toString())); + throw new IOException(String.format("Failed deserialization for {{classname}}: no class matches result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())); } }.nullSafe(); } @@ -127,9 +208,11 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im {{/anyOf}} static { + {{#composedSchemas}} {{#anyOf}} - schemas.put("{{{.}}}", {{{.}}}.class); + schemas.put("{{{dataType}}}", {{{baseType}}}.class); {{/anyOf}} + {{/composedSchemas}} } @Override @@ -143,7 +226,6 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im * {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}} * * It could be an instance of the 'anyOf' schemas. - * The anyOf child schemas may themselves be a composed schema (allOf, anyOf, anyOf). */ @Override public void setActualInstance(Object instance) { @@ -154,13 +236,24 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im } {{/isNullable}} + {{#composedSchemas}} {{#anyOf}} - if (instance instanceof {{{.}}}) { + if (instance instanceof {{#isArray}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) { + {{#isArray}} + List list = (List) instance; + if(list.get(0) instanceof {{complexType}}) { + super.setActualInstance(instance); + return; + } + {{/isArray}} + {{^isArray}} super.setActualInstance(instance); return; + {{/isArray}} } {{/anyOf}} + {{/composedSchemas}} throw new RuntimeException("Invalid instance type. Must be {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}"); } @@ -175,19 +268,20 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im return super.getActualInstance(); } + {{#composedSchemas}} {{#anyOf}} /** - * Get the actual instance of `{{{.}}}`. If the actual instance is not `{{{.}}}`, + * Get the actual instance of `{{{dataType}}}`. If the actual instance is not `{{{dataType}}}`, * the ClassCastException will be thrown. * - * @return The actual instance of `{{{.}}}` - * @throws ClassCastException if the instance is not `{{{.}}}` + * @return The actual instance of `{{{dataType}}}` + * @throws ClassCastException if the instance is not `{{{dataType}}}` */ - public {{{.}}} get{{{.}}}() throws ClassCastException { - return ({{{.}}})super.getActualInstance(); + public {{{dataType}}} get{{#isArray}}{{complexType}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}() throws ClassCastException { + return ({{{dataType}}})super.getActualInstance(); } - {{/anyOf}} + {{/composedSchemas}} /** * Validates the JSON Element and throws an exception if issues found @@ -197,20 +291,69 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im */ public static void validateJsonElement(JsonElement jsonElement) throws IOException { // validate anyOf schemas one by one - int validCount = 0; + ArrayList errorMessages = new ArrayList<>(); + {{#composedSchemas}} {{#anyOf}} - // validate the json string with {{{.}}} + // validate the json string with {{{dataType}}} try { + {{^hasVars}} + {{#isNumber}} + if(!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isNumber}} + {{^isNumber}} + {{#isPrimitiveType}} + if(!jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{^isArray}} + {{{dataType}}}.validateJsonElement(jsonElement); + {{/isArray}} + {{/isPrimitiveType}} + {{/isNumber}} + {{#isArray}} + if (!jsonElement.isJsonArray()) { + throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString())); + } + JsonArray array = jsonElement.getAsJsonArray(); + // validate array items + for(JsonElement element : array) { + {{#items}} + {{#isNumber}} + if(!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isNumber}} + {{^isNumber}} + {{#isPrimitiveType}} + if(!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{{dataType}}}.validateJsonElement(element); + {{/isPrimitiveType}} + {{/isNumber}} + {{/items}} + } + {{/isArray}} + {{/hasVars}} + {{#hasVars}} {{{.}}}.validateJsonElement(jsonElement); - return; // return earlier as at least one schema is valid with respect to the Json object - //validCount++; + return; + {{/hasVars}} + return; } catch (Exception e) { + errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage())); // continue to the next one } {{/anyOf}} - if (validCount == 0) { - throw new IOException(String.format("The JSON string is invalid for {{classname}} with anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}. JSON: %s", jsonElement.toString())); - } + {{/composedSchemas}} + throw new IOException(String.format("The JSON string is invalid for {{classname}} with anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}. no class match the result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())); + } /** diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/oneof_model.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/oneof_model.mustache index bb601f2ae69..c89bbac73a0 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/oneof_model.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/oneof_model.mustache @@ -254,7 +254,6 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im * {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}} * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/modules/openapi-generator/src/test/resources/3_0/java/petstore-with-fake-endpoints-models-for-testing-okhttp-gson.yaml b/modules/openapi-generator/src/test/resources/3_0/java/petstore-with-fake-endpoints-models-for-testing-okhttp-gson.yaml index 460bb4223df..92dafde5e0d 100644 --- a/modules/openapi-generator/src/test/resources/3_0/java/petstore-with-fake-endpoints-models-for-testing-okhttp-gson.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/java/petstore-with-fake-endpoints-models-for-testing-okhttp-gson.yaml @@ -2308,6 +2308,13 @@ components: maxLength: 1089 - type: number - type: boolean + ScalarAnyOf: + description: Values of scalar type using anyOf + anyOf: + - type: string + maxLength: 1089 + - type: number + - type: boolean Array: description: Values of array type type: array diff --git a/samples/client/others/java/okhttp-gson-streaming/src/main/java/org/openapitools/client/model/SimpleOneOf.java b/samples/client/others/java/okhttp-gson-streaming/src/main/java/org/openapitools/client/model/SimpleOneOf.java index 36de4fc0b02..b2ba7f054dd 100644 --- a/samples/client/others/java/okhttp-gson-streaming/src/main/java/org/openapitools/client/model/SimpleOneOf.java +++ b/samples/client/others/java/okhttp-gson-streaming/src/main/java/org/openapitools/client/model/SimpleOneOf.java @@ -173,7 +173,6 @@ public class SimpleOneOf extends AbstractOpenApiSchema implements Serializable { * Integer, String * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/.openapi-generator/FILES b/samples/client/petstore/java/okhttp-gson/.openapi-generator/FILES index 8a32ed68279..aebc1680656 100644 --- a/samples/client/petstore/java/okhttp-gson/.openapi-generator/FILES +++ b/samples/client/petstore/java/okhttp-gson/.openapi-generator/FILES @@ -80,6 +80,7 @@ docs/Quadrilateral.md docs/QuadrilateralInterface.md docs/ReadOnlyFirst.md docs/Scalar.md +docs/ScalarAnyOf.md docs/ScaleneTriangle.md docs/Shape.md docs/ShapeInterface.md @@ -206,6 +207,7 @@ 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 src/main/java/org/openapitools/client/model/Scalar.java +src/main/java/org/openapitools/client/model/ScalarAnyOf.java src/main/java/org/openapitools/client/model/ScaleneTriangle.java src/main/java/org/openapitools/client/model/Shape.java src/main/java/org/openapitools/client/model/ShapeInterface.java diff --git a/samples/client/petstore/java/okhttp-gson/README.md b/samples/client/petstore/java/okhttp-gson/README.md index 6098ec22136..87b6205eeac 100644 --- a/samples/client/petstore/java/okhttp-gson/README.md +++ b/samples/client/petstore/java/okhttp-gson/README.md @@ -229,6 +229,7 @@ Class | Method | HTTP request | Description - [QuadrilateralInterface](docs/QuadrilateralInterface.md) - [ReadOnlyFirst](docs/ReadOnlyFirst.md) - [Scalar](docs/Scalar.md) + - [ScalarAnyOf](docs/ScalarAnyOf.md) - [ScaleneTriangle](docs/ScaleneTriangle.md) - [Shape](docs/Shape.md) - [ShapeInterface](docs/ShapeInterface.md) diff --git a/samples/client/petstore/java/okhttp-gson/api/openapi.yaml b/samples/client/petstore/java/okhttp-gson/api/openapi.yaml index 9bb8dc69d5f..338e360f674 100644 --- a/samples/client/petstore/java/okhttp-gson/api/openapi.yaml +++ b/samples/client/petstore/java/okhttp-gson/api/openapi.yaml @@ -2315,6 +2315,13 @@ components: type: string - type: number - type: boolean + ScalarAnyOf: + anyOf: + - maxLength: 1089 + type: string + - type: number + - type: boolean + description: Values of scalar type using anyOf Array: description: Values of array type items: diff --git a/samples/client/petstore/java/okhttp-gson/docs/ScalarAnyOf.md b/samples/client/petstore/java/okhttp-gson/docs/ScalarAnyOf.md new file mode 100644 index 00000000000..767e9196023 --- /dev/null +++ b/samples/client/petstore/java/okhttp-gson/docs/ScalarAnyOf.md @@ -0,0 +1,13 @@ + + +# ScalarAnyOf + +Values of scalar type using anyOf + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| + + + diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/JSON.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/JSON.java index 49b17f67e35..6b93a63176a 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/JSON.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/JSON.java @@ -292,6 +292,7 @@ public class JSON { gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.QuadrilateralInterface.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.ReadOnlyFirst.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.Scalar.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.ScalarAnyOf.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.ScaleneTriangle.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.Shape.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.ShapeInterface.CustomTypeAdapterFactory()); diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Fruit.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Fruit.java index ed9086569f5..f15e589e223 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Fruit.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Fruit.java @@ -177,7 +177,6 @@ public class Fruit extends AbstractOpenApiSchema { * Apple, Banana * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/FruitReq.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/FruitReq.java index cea09015a8c..0cfe7eae96a 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/FruitReq.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/FruitReq.java @@ -177,7 +177,6 @@ public class FruitReq extends AbstractOpenApiSchema { * AppleReq, BananaReq * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/GmFruit.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/GmFruit.java index 2b76a56bc05..298f1177b4a 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/GmFruit.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/GmFruit.java @@ -35,6 +35,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import com.google.gson.Gson; @@ -54,6 +55,7 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonArray; import com.google.gson.JsonParseException; import org.openapitools.client.JSON; @@ -83,19 +85,17 @@ public class GmFruit extends AbstractOpenApiSchema { // check if the actual instance is of the type `Apple` if (value.getActualInstance() instanceof Apple) { - JsonObject obj = adapterApple.toJsonTree((Apple)value.getActualInstance()).getAsJsonObject(); - elementAdapter.write(out, obj); - return; + JsonElement element = adapterApple.toJsonTree((Apple)value.getActualInstance()); + elementAdapter.write(out, element); + 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; + JsonElement element = adapterBanana.toJsonTree((Banana)value.getActualInstance()); + elementAdapter.write(out, element); + return; } - - throw new IOException("Failed to serialize as the type doesn't match anyOf schemas: Apple, Banana"); + throw new IOException("Failed to serialize as the type doesn't match anyOf schemae: Apple, Banana"); } @Override @@ -103,34 +103,37 @@ public class GmFruit extends AbstractOpenApiSchema { Object deserialized = null; JsonElement jsonElement = elementAdapter.read(in); + ArrayList errorMessages = new ArrayList<>(); + TypeAdapter actualAdapter = elementAdapter; + // deserialize Apple try { - // validate the JSON object to see if any exception is thrown - Apple.validateJsonElement(jsonElement); - log.log(Level.FINER, "Input data matches schema 'Apple'"); - GmFruit ret = new GmFruit(); - ret.setActualInstance(adapterApple.fromJsonTree(jsonElement)); - return ret; + // validate the JSON object to see if any exception is thrown + Apple.validateJsonElement(jsonElement); + actualAdapter = adapterApple; + GmFruit ret = new GmFruit(); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); + return ret; } catch (Exception e) { - // deserialization failed, continue - log.log(Level.FINER, "Input data does not match schema 'Apple'", e); + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for Apple failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema 'Apple'", e); } - // deserialize Banana try { - // validate the JSON object to see if any exception is thrown - Banana.validateJsonElement(jsonElement); - log.log(Level.FINER, "Input data matches schema 'Banana'"); - GmFruit ret = new GmFruit(); - ret.setActualInstance(adapterBanana.fromJsonTree(jsonElement)); - return ret; + // validate the JSON object to see if any exception is thrown + Banana.validateJsonElement(jsonElement); + actualAdapter = adapterBanana; + GmFruit ret = new GmFruit(); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); + return ret; } catch (Exception e) { - // deserialization failed, continue - log.log(Level.FINER, "Input data does not match schema 'Banana'", e); + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for Banana failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema 'Banana'", e); } - - throw new IOException(String.format("Failed deserialization for GmFruit: no class matched. JSON: %s", jsonElement.toString())); + throw new IOException(String.format("Failed deserialization for GmFruit: no class matches result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())); } }.nullSafe(); } @@ -169,7 +172,6 @@ public class GmFruit extends AbstractOpenApiSchema { * Apple, Banana * * It could be an instance of the 'anyOf' schemas. - * The anyOf child schemas may themselves be a composed schema (allOf, anyOf, anyOf). */ @Override public void setActualInstance(Object instance) { @@ -207,7 +209,6 @@ public class GmFruit extends AbstractOpenApiSchema { public Apple getApple() throws ClassCastException { return (Apple)super.getActualInstance(); } - /** * Get the actual instance of `Banana`. If the actual instance is not `Banana`, * the ClassCastException will be thrown. @@ -219,7 +220,6 @@ public class GmFruit extends AbstractOpenApiSchema { return (Banana)super.getActualInstance(); } - /** * Validates the JSON Element and throws an exception if issues found * @@ -228,26 +228,25 @@ public class GmFruit extends AbstractOpenApiSchema { */ public static void validateJsonElement(JsonElement jsonElement) throws IOException { // validate anyOf schemas one by one - int validCount = 0; + ArrayList errorMessages = new ArrayList<>(); // validate the json string with Apple try { Apple.validateJsonElement(jsonElement); - return; // return earlier as at least one schema is valid with respect to the Json object - //validCount++; + return; } catch (Exception e) { + errorMessages.add(String.format("Deserialization for Apple failed with `%s`.", e.getMessage())); // continue to the next one } // validate the json string with Banana try { Banana.validateJsonElement(jsonElement); - return; // return earlier as at least one schema is valid with respect to the Json object - //validCount++; + return; } catch (Exception e) { + errorMessages.add(String.format("Deserialization for Banana failed with `%s`.", e.getMessage())); // continue to the next one } - if (validCount == 0) { - throw new IOException(String.format("The JSON string is invalid for GmFruit with anyOf schemas: Apple, Banana. JSON: %s", jsonElement.toString())); - } + throw new IOException(String.format("The JSON string is invalid for GmFruit with anyOf schemas: Apple, Banana. no class match the result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())); + } /** diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Mammal.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Mammal.java index b0c27a52d95..c136cf40fc2 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Mammal.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Mammal.java @@ -228,7 +228,6 @@ public class Mammal extends AbstractOpenApiSchema { * Pig, Whale, Zebra * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/NullableShape.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/NullableShape.java index be908198855..963dcf116df 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/NullableShape.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/NullableShape.java @@ -198,7 +198,6 @@ public class NullableShape extends AbstractOpenApiSchema { * Quadrilateral, Triangle * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Pig.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Pig.java index ba2fb7461cb..c14df08b7a0 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Pig.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Pig.java @@ -198,7 +198,6 @@ public class Pig extends AbstractOpenApiSchema { * BasquePig, DanishPig * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Quadrilateral.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Quadrilateral.java index 78b2897e0ac..4ce2346d7b6 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Quadrilateral.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Quadrilateral.java @@ -198,7 +198,6 @@ public class Quadrilateral extends AbstractOpenApiSchema { * ComplexQuadrilateral, SimpleQuadrilateral * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Scalar.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Scalar.java index a5262207df4..d148278033e 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Scalar.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Scalar.java @@ -200,7 +200,6 @@ public class Scalar extends AbstractOpenApiSchema { * BigDecimal, Boolean, String * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ScalarAnyOf.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ScalarAnyOf.java new file mode 100644 index 00000000000..3a7249fda53 --- /dev/null +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ScalarAnyOf.java @@ -0,0 +1,325 @@ +/* + * 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 java.math.BigDecimal; + + + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.JsonPrimitive; +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 com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonParseException; + +import org.openapitools.client.JSON; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") +public class ScalarAnyOf extends AbstractOpenApiSchema { + private static final Logger log = Logger.getLogger(ScalarAnyOf.class.getName()); + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ScalarAnyOf.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ScalarAnyOf' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter adapterString = gson.getDelegateAdapter(this, TypeToken.get(String.class)); + final TypeAdapter adapterBigDecimal = gson.getDelegateAdapter(this, TypeToken.get(BigDecimal.class)); + final TypeAdapter adapterBoolean = gson.getDelegateAdapter(this, TypeToken.get(Boolean.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ScalarAnyOf value) throws IOException { + if (value == null || value.getActualInstance() == null) { + elementAdapter.write(out, null); + return; + } + + // check if the actual instance is of the type `String` + if (value.getActualInstance() instanceof String) { + JsonPrimitive primitive = adapterString.toJsonTree((String)value.getActualInstance()).getAsJsonPrimitive(); + elementAdapter.write(out, primitive); + return; + } + // check if the actual instance is of the type `BigDecimal` + if (value.getActualInstance() instanceof BigDecimal) { + JsonElement element = adapterBigDecimal.toJsonTree((BigDecimal)value.getActualInstance()); + elementAdapter.write(out, element); + return; + } + // check if the actual instance is of the type `Boolean` + if (value.getActualInstance() instanceof Boolean) { + JsonPrimitive primitive = adapterBoolean.toJsonTree((Boolean)value.getActualInstance()).getAsJsonPrimitive(); + elementAdapter.write(out, primitive); + return; + } + throw new IOException("Failed to serialize as the type doesn't match anyOf schemae: BigDecimal, Boolean, String"); + } + + @Override + public ScalarAnyOf read(JsonReader in) throws IOException { + Object deserialized = null; + JsonElement jsonElement = elementAdapter.read(in); + + ArrayList errorMessages = new ArrayList<>(); + TypeAdapter actualAdapter = elementAdapter; + + // deserialize String + try { + // validate the JSON object to see if any exception is thrown + if(!jsonElement.getAsJsonPrimitive().isString()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type String in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapterString; + ScalarAnyOf ret = new ScalarAnyOf(); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); + return ret; + } catch (Exception e) { + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for String failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema 'String'", e); + } + // deserialize BigDecimal + try { + // validate the JSON object to see if any exception is thrown + if(!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapterBigDecimal; + ScalarAnyOf ret = new ScalarAnyOf(); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); + return ret; + } catch (Exception e) { + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for BigDecimal failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema 'BigDecimal'", e); + } + // deserialize Boolean + try { + // validate the JSON object to see if any exception is thrown + if(!jsonElement.getAsJsonPrimitive().isBoolean()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Boolean in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapterBoolean; + ScalarAnyOf ret = new ScalarAnyOf(); + ret.setActualInstance(actualAdapter.fromJsonTree(jsonElement)); + return ret; + } catch (Exception e) { + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for Boolean failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema 'Boolean'", e); + } + + throw new IOException(String.format("Failed deserialization for ScalarAnyOf: no class matches result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())); + } + }.nullSafe(); + } + } + + // store a list of schema names defined in anyOf + public static final Map> schemas = new HashMap>(); + + public ScalarAnyOf() { + super("anyOf", Boolean.FALSE); + } + + public ScalarAnyOf(BigDecimal o) { + super("anyOf", Boolean.FALSE); + setActualInstance(o); + } + + public ScalarAnyOf(Boolean o) { + super("anyOf", Boolean.FALSE); + setActualInstance(o); + } + + public ScalarAnyOf(String o) { + super("anyOf", Boolean.FALSE); + setActualInstance(o); + } + + static { + schemas.put("String", String.class); + schemas.put("BigDecimal", BigDecimal.class); + schemas.put("Boolean", Boolean.class); + } + + @Override + public Map> getSchemas() { + return ScalarAnyOf.schemas; + } + + /** + * Set the instance that matches the anyOf child schema, check + * the instance parameter is valid against the anyOf child schemas: + * BigDecimal, Boolean, String + * + * It could be an instance of the 'anyOf' schemas. + */ + @Override + public void setActualInstance(Object instance) { + if (instance instanceof String) { + super.setActualInstance(instance); + return; + } + + if (instance instanceof BigDecimal) { + super.setActualInstance(instance); + return; + } + + if (instance instanceof Boolean) { + super.setActualInstance(instance); + return; + } + + throw new RuntimeException("Invalid instance type. Must be BigDecimal, Boolean, String"); + } + + /** + * Get the actual instance, which can be the following: + * BigDecimal, Boolean, String + * + * @return The actual instance (BigDecimal, Boolean, String) + */ + @Override + public Object getActualInstance() { + return super.getActualInstance(); + } + + /** + * Get the actual instance of `String`. If the actual instance is not `String`, + * the ClassCastException will be thrown. + * + * @return The actual instance of `String` + * @throws ClassCastException if the instance is not `String` + */ + public String getString() throws ClassCastException { + return (String)super.getActualInstance(); + } + /** + * Get the actual instance of `BigDecimal`. If the actual instance is not `BigDecimal`, + * the ClassCastException will be thrown. + * + * @return The actual instance of `BigDecimal` + * @throws ClassCastException if the instance is not `BigDecimal` + */ + public BigDecimal getBigDecimal() throws ClassCastException { + return (BigDecimal)super.getActualInstance(); + } + /** + * Get the actual instance of `Boolean`. If the actual instance is not `Boolean`, + * the ClassCastException will be thrown. + * + * @return The actual instance of `Boolean` + * @throws ClassCastException if the instance is not `Boolean` + */ + public Boolean getBoolean() throws ClassCastException { + return (Boolean)super.getActualInstance(); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ScalarAnyOf + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + // validate anyOf schemas one by one + ArrayList errorMessages = new ArrayList<>(); + // validate the json string with String + try { + if(!jsonElement.getAsJsonPrimitive().isString()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type String in the JSON string but got `%s`", jsonElement.toString())); + } + return; + } catch (Exception e) { + errorMessages.add(String.format("Deserialization for String failed with `%s`.", e.getMessage())); + // continue to the next one + } + // validate the json string with BigDecimal + try { + if(!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + return; + } catch (Exception e) { + errorMessages.add(String.format("Deserialization for BigDecimal failed with `%s`.", e.getMessage())); + // continue to the next one + } + // validate the json string with Boolean + try { + if(!jsonElement.getAsJsonPrimitive().isBoolean()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Boolean in the JSON string but got `%s`", jsonElement.toString())); + } + return; + } catch (Exception e) { + errorMessages.add(String.format("Deserialization for Boolean failed with `%s`.", e.getMessage())); + // continue to the next one + } + throw new IOException(String.format("The JSON string is invalid for ScalarAnyOf with anyOf schemas: BigDecimal, Boolean, String. no class match the result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())); + + } + + /** + * Create an instance of ScalarAnyOf given an JSON string + * + * @param jsonString JSON string + * @return An instance of ScalarAnyOf + * @throws IOException if the JSON string is invalid with respect to ScalarAnyOf + */ + public static ScalarAnyOf fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ScalarAnyOf.class); + } + + /** + * Convert an instance of ScalarAnyOf to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Shape.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Shape.java index 0773e76bbb2..eee36ea61e6 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Shape.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Shape.java @@ -198,7 +198,6 @@ public class Shape extends AbstractOpenApiSchema { * Quadrilateral, Triangle * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ShapeOrNull.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ShapeOrNull.java index 964c6590fad..407c74dac26 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ShapeOrNull.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/ShapeOrNull.java @@ -198,7 +198,6 @@ public class ShapeOrNull extends AbstractOpenApiSchema { * Quadrilateral, Triangle * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Triangle.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Triangle.java index 07ce9117d0f..85a04e6b1be 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Triangle.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Triangle.java @@ -228,7 +228,6 @@ public class Triangle extends AbstractOpenApiSchema { * EquilateralTriangle, IsoscelesTriangle, ScaleneTriangle * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Value.java b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Value.java index 5e4ddd08ced..06847148f65 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Value.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/org/openapitools/client/model/Value.java @@ -182,7 +182,6 @@ public class Value extends AbstractOpenApiSchema { * List, Scalar * * It could be an instance of the 'oneOf' schemas. - * The oneOf child schemas may themselves be a composed schema (allOf, anyOf, oneOf). */ @Override public void setActualInstance(Object instance) { diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/JSONTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/JSONTest.java index 035ae0b9967..f793793692b 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/JSONTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/JSONTest.java @@ -740,4 +740,39 @@ public class JSONTest { p.setTypeWithUnderscore("test3"); assertEquals(json.getGson().toJson(p), "{\"_type\":\"test1\",\"type\":\"test2\",\"type_\":\"test3\"}"); } + + /** + * Validate a anyOf schema can be deserialized into the expected class. + * The anyOf schema contains primitive Types. + */ + @Test + public void testAnyOfSchemaWithPrimitives() throws Exception { + { + // string test + String str = "\"just a string\""; + ScalarAnyOf s = json.getGson().fromJson(str, ScalarAnyOf.class); + assertTrue(s.getActualInstance() instanceof String); + assertEquals(json.getGson().toJson(s), str); + } + { + // number test + String str = "123.45"; + ScalarAnyOf s = json.getGson().fromJson(str, ScalarAnyOf.class); + assertTrue(s.getActualInstance() instanceof BigDecimal); + assertEquals(json.getGson().toJson(s), str); + } + { + // boolean test + String str = "true"; + ScalarAnyOf s = json.getGson().fromJson(str, ScalarAnyOf.class); + assertTrue(s.getActualInstance() instanceof Boolean); + assertEquals(json.getGson().toJson(s), str); + } + + // test no match + com.google.gson.JsonSyntaxException thrown = Assertions.assertThrows(com.google.gson.JsonSyntaxException.class, () -> { + String str = "{\"id\": 5847, \"name\":\"tag test 1\"}"; + ScalarAnyOf s = json.getGson().fromJson(str, ScalarAnyOf.class); + }); + } } diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/model/ScalarAnyOfTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/model/ScalarAnyOfTest.java new file mode 100644 index 00000000000..489c4f9a253 --- /dev/null +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/org/openapitools/client/model/ScalarAnyOfTest.java @@ -0,0 +1,34 @@ +/* + * 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.math.BigDecimal; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +/** + * Model tests for ScalarAnyOf + */ +public class ScalarAnyOfTest { + private final ScalarAnyOf model = new ScalarAnyOf(); + + /** + * Model tests for ScalarAnyOf + */ + @Test + public void testScalarAnyOf() { + // TODO: test ScalarAnyOf + } + +}