From 03e8aee8ea415eadf70290916c3c290759a0b2fb Mon Sep 17 00:00:00 2001 From: Slavek Kabrda Date: Thu, 23 Jul 2020 10:33:15 +0200 Subject: [PATCH] [java][jersey2-client] Disable coercion of scalars (#6811) * [java][jersey2-client] Disable coercion of scalars * Respect the coercion objectmapper setting in deserializers * Update jackson in maven plugin to get version that has ALLOW_COERCION_OF_SCALARS --- .../examples/java-client.xml | 2 +- .../examples/kotlin.xml | 2 +- .../examples/multi-module/pom.xml | 2 +- .../Java/libraries/jersey2/JSON.mustache | 1 + .../libraries/jersey2/oneof_model.mustache | 32 ++++++-- .../java/org/openapitools/client/JSON.java | 1 + .../java/org/openapitools/client/JSON.java | 1 + .../org/openapitools/client/model/Fruit.java | 54 ++++++++++--- .../openapitools/client/model/FruitReq.java | 56 ++++++++++--- .../org/openapitools/client/model/Mammal.java | 79 ++++++++++++++----- .../client/model/NullableShape.java | 56 ++++++++++--- .../org/openapitools/client/model/Pig.java | 54 ++++++++++--- .../client/model/Quadrilateral.java | 54 ++++++++++--- .../org/openapitools/client/model/Shape.java | 54 ++++++++++--- .../client/model/ShapeOrNull.java | 56 ++++++++++--- .../openapitools/client/model/Triangle.java | 79 ++++++++++++++----- 16 files changed, 454 insertions(+), 129 deletions(-) diff --git a/modules/openapi-generator-maven-plugin/examples/java-client.xml b/modules/openapi-generator-maven-plugin/examples/java-client.xml index c22f4cfcce9..c966e5c63ee 100644 --- a/modules/openapi-generator-maven-plugin/examples/java-client.xml +++ b/modules/openapi-generator-maven-plugin/examples/java-client.xml @@ -185,7 +185,7 @@ 1.5.8 2.27 - 2.8.9 + 2.9.10 0.2.0 2.7 1.0.0 diff --git a/modules/openapi-generator-maven-plugin/examples/kotlin.xml b/modules/openapi-generator-maven-plugin/examples/kotlin.xml index 130a359b06a..51b21f3030e 100644 --- a/modules/openapi-generator-maven-plugin/examples/kotlin.xml +++ b/modules/openapi-generator-maven-plugin/examples/kotlin.xml @@ -224,7 +224,7 @@ 1.5.8 2.27 - 2.8.9 + 2.9.10 0.2.0 2.7 1.0.0 diff --git a/modules/openapi-generator-maven-plugin/examples/multi-module/pom.xml b/modules/openapi-generator-maven-plugin/examples/multi-module/pom.xml index c8a89982992..f63c803d62d 100644 --- a/modules/openapi-generator-maven-plugin/examples/multi-module/pom.xml +++ b/modules/openapi-generator-maven-plugin/examples/multi-module/pom.xml @@ -15,7 +15,7 @@ 1.5.8 2.27 - 2.8.9 + 2.9.10 0.2.0 2.7 1.0.0 diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/JSON.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/JSON.mustache index bcc075ac9fc..2820eaa4bb1 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/JSON.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/JSON.mustache @@ -34,6 +34,7 @@ public class JSON implements ContextResolver { public JSON() { mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, true); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/oneof_model.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/oneof_model.mustache index dedc9d634f7..f3a51dccdc0 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/oneof_model.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/oneof_model.mustache @@ -10,10 +10,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -73,16 +75,34 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im {{/discriminator}} {{/useOneOfDiscriminatorLookup}} + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); {{#oneOf}} // deserialize {{{.}}} try { - deserialized = tree.traverse(jp.getCodec()).readValueAs({{{.}}}.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema '{{{.}}}'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if ({{{.}}}.class.equals(Integer.class) || {{{.}}}.class.equals(Long.class) || {{{.}}}.class.equals(Float.class) || {{{.}}}.class.equals(Double.class) || {{{.}}}.class.equals(Boolean.class) || {{{.}}}.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= (({{{.}}}.class.equals(Integer.class) || {{{.}}}.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= (({{{.}}}.class.equals(Float.class) || {{{.}}}.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= ({{{.}}}.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= ({{{.}}}.class.equals(String.class) && token == JsonToken.VALUE_STRING); + {{#isNullable}} + attemptParsing |= (token == JsonToken.VALUE_NULL); + {{/isNullable}} + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs({{{.}}}.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema '{{{.}}}'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e); diff --git a/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java b/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java index 9d748f6e7c2..d29b48becb1 100644 --- a/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java +++ b/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java @@ -21,6 +21,7 @@ public class JSON implements ContextResolver { public JSON() { mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, true); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java index 9d748f6e7c2..d29b48becb1 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/JSON.java @@ -21,6 +21,7 @@ public class JSON implements ContextResolver { public JSON() { mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, true); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Fruit.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Fruit.java index 0d482282095..b7c2f836414 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Fruit.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Fruit.java @@ -44,10 +44,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -89,15 +91,30 @@ public class Fruit extends AbstractOpenApiSchema { public Fruit deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode tree = jp.readValueAsTree(); Object deserialized = null; + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize Apple try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Apple.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Apple'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Apple.class.equals(Integer.class) || Apple.class.equals(Long.class) || Apple.class.equals(Float.class) || Apple.class.equals(Double.class) || Apple.class.equals(Boolean.class) || Apple.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Apple.class.equals(Integer.class) || Apple.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Apple.class.equals(Float.class) || Apple.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Apple.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Apple.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Apple.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Apple'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Apple'", e); @@ -105,12 +122,25 @@ public class Fruit extends AbstractOpenApiSchema { // deserialize Banana try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Banana.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Banana'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Banana.class.equals(Integer.class) || Banana.class.equals(Long.class) || Banana.class.equals(Float.class) || Banana.class.equals(Double.class) || Banana.class.equals(Boolean.class) || Banana.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Banana.class.equals(Integer.class) || Banana.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Banana.class.equals(Float.class) || Banana.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Banana.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Banana.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Banana.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Banana'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Banana'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/FruitReq.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/FruitReq.java index ba0fc1a2bf7..e780f72ecb8 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/FruitReq.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/FruitReq.java @@ -44,10 +44,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -89,15 +91,31 @@ public class FruitReq extends AbstractOpenApiSchema { public FruitReq deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode tree = jp.readValueAsTree(); Object deserialized = null; + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize AppleReq try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(AppleReq.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'AppleReq'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (AppleReq.class.equals(Integer.class) || AppleReq.class.equals(Long.class) || AppleReq.class.equals(Float.class) || AppleReq.class.equals(Double.class) || AppleReq.class.equals(Boolean.class) || AppleReq.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((AppleReq.class.equals(Integer.class) || AppleReq.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((AppleReq.class.equals(Float.class) || AppleReq.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (AppleReq.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (AppleReq.class.equals(String.class) && token == JsonToken.VALUE_STRING); + attemptParsing |= (token == JsonToken.VALUE_NULL); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(AppleReq.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'AppleReq'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'AppleReq'", e); @@ -105,12 +123,26 @@ public class FruitReq extends AbstractOpenApiSchema { // deserialize BananaReq try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(BananaReq.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'BananaReq'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (BananaReq.class.equals(Integer.class) || BananaReq.class.equals(Long.class) || BananaReq.class.equals(Float.class) || BananaReq.class.equals(Double.class) || BananaReq.class.equals(Boolean.class) || BananaReq.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((BananaReq.class.equals(Integer.class) || BananaReq.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((BananaReq.class.equals(Float.class) || BananaReq.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (BananaReq.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (BananaReq.class.equals(String.class) && token == JsonToken.VALUE_STRING); + attemptParsing |= (token == JsonToken.VALUE_NULL); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(BananaReq.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'BananaReq'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'BananaReq'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Mammal.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Mammal.java index db1f6b9b5e1..ae0b2f3d97e 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Mammal.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Mammal.java @@ -50,10 +50,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -115,15 +117,30 @@ public class Mammal extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for Mammal. Possible values: Pig whale zebra", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize Pig try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Pig.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Pig'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Pig.class.equals(Integer.class) || Pig.class.equals(Long.class) || Pig.class.equals(Float.class) || Pig.class.equals(Double.class) || Pig.class.equals(Boolean.class) || Pig.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Pig.class.equals(Integer.class) || Pig.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Pig.class.equals(Float.class) || Pig.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Pig.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Pig.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Pig.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Pig'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Pig'", e); @@ -131,12 +148,25 @@ public class Mammal extends AbstractOpenApiSchema { // deserialize Whale try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Whale.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Whale'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Whale.class.equals(Integer.class) || Whale.class.equals(Long.class) || Whale.class.equals(Float.class) || Whale.class.equals(Double.class) || Whale.class.equals(Boolean.class) || Whale.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Whale.class.equals(Integer.class) || Whale.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Whale.class.equals(Float.class) || Whale.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Whale.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Whale.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Whale.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Whale'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Whale'", e); @@ -144,12 +174,25 @@ public class Mammal extends AbstractOpenApiSchema { // deserialize Zebra try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Zebra.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Zebra'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Zebra.class.equals(Integer.class) || Zebra.class.equals(Long.class) || Zebra.class.equals(Float.class) || Zebra.class.equals(Double.class) || Zebra.class.equals(Boolean.class) || Zebra.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Zebra.class.equals(Integer.class) || Zebra.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Zebra.class.equals(Float.class) || Zebra.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Zebra.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Zebra.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Zebra.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Zebra'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Zebra'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/NullableShape.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/NullableShape.java index bcc0fc2b1c6..7807b98979e 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/NullableShape.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/NullableShape.java @@ -49,10 +49,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -110,15 +112,31 @@ public class NullableShape extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for NullableShape. Possible values: Quadrilateral Triangle", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize Quadrilateral try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Quadrilateral.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Quadrilateral'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Quadrilateral.class.equals(Integer.class) || Quadrilateral.class.equals(Long.class) || Quadrilateral.class.equals(Float.class) || Quadrilateral.class.equals(Double.class) || Quadrilateral.class.equals(Boolean.class) || Quadrilateral.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Quadrilateral.class.equals(Integer.class) || Quadrilateral.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Quadrilateral.class.equals(Float.class) || Quadrilateral.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Quadrilateral.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Quadrilateral.class.equals(String.class) && token == JsonToken.VALUE_STRING); + attemptParsing |= (token == JsonToken.VALUE_NULL); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Quadrilateral.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Quadrilateral'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Quadrilateral'", e); @@ -126,12 +144,26 @@ public class NullableShape extends AbstractOpenApiSchema { // deserialize Triangle try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Triangle.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Triangle'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Triangle.class.equals(Integer.class) || Triangle.class.equals(Long.class) || Triangle.class.equals(Float.class) || Triangle.class.equals(Double.class) || Triangle.class.equals(Boolean.class) || Triangle.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Triangle.class.equals(Integer.class) || Triangle.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Triangle.class.equals(Float.class) || Triangle.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Triangle.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Triangle.class.equals(String.class) && token == JsonToken.VALUE_STRING); + attemptParsing |= (token == JsonToken.VALUE_NULL); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Triangle.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Triangle'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Triangle'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Pig.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Pig.java index a43bf499aac..a2e751069a3 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Pig.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Pig.java @@ -49,10 +49,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -110,15 +112,30 @@ public class Pig extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for Pig. Possible values: BasquePig DanishPig", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize BasquePig try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(BasquePig.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'BasquePig'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (BasquePig.class.equals(Integer.class) || BasquePig.class.equals(Long.class) || BasquePig.class.equals(Float.class) || BasquePig.class.equals(Double.class) || BasquePig.class.equals(Boolean.class) || BasquePig.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((BasquePig.class.equals(Integer.class) || BasquePig.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((BasquePig.class.equals(Float.class) || BasquePig.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (BasquePig.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (BasquePig.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(BasquePig.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'BasquePig'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'BasquePig'", e); @@ -126,12 +143,25 @@ public class Pig extends AbstractOpenApiSchema { // deserialize DanishPig try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(DanishPig.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'DanishPig'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (DanishPig.class.equals(Integer.class) || DanishPig.class.equals(Long.class) || DanishPig.class.equals(Float.class) || DanishPig.class.equals(Double.class) || DanishPig.class.equals(Boolean.class) || DanishPig.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((DanishPig.class.equals(Integer.class) || DanishPig.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((DanishPig.class.equals(Float.class) || DanishPig.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (DanishPig.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (DanishPig.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(DanishPig.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'DanishPig'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'DanishPig'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Quadrilateral.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Quadrilateral.java index 16f69333948..8e892e346b3 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Quadrilateral.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Quadrilateral.java @@ -49,10 +49,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -110,15 +112,30 @@ public class Quadrilateral extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for Quadrilateral. Possible values: ComplexQuadrilateral SimpleQuadrilateral", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize ComplexQuadrilateral try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(ComplexQuadrilateral.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'ComplexQuadrilateral'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (ComplexQuadrilateral.class.equals(Integer.class) || ComplexQuadrilateral.class.equals(Long.class) || ComplexQuadrilateral.class.equals(Float.class) || ComplexQuadrilateral.class.equals(Double.class) || ComplexQuadrilateral.class.equals(Boolean.class) || ComplexQuadrilateral.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((ComplexQuadrilateral.class.equals(Integer.class) || ComplexQuadrilateral.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((ComplexQuadrilateral.class.equals(Float.class) || ComplexQuadrilateral.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (ComplexQuadrilateral.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (ComplexQuadrilateral.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(ComplexQuadrilateral.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'ComplexQuadrilateral'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'ComplexQuadrilateral'", e); @@ -126,12 +143,25 @@ public class Quadrilateral extends AbstractOpenApiSchema { // deserialize SimpleQuadrilateral try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(SimpleQuadrilateral.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'SimpleQuadrilateral'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (SimpleQuadrilateral.class.equals(Integer.class) || SimpleQuadrilateral.class.equals(Long.class) || SimpleQuadrilateral.class.equals(Float.class) || SimpleQuadrilateral.class.equals(Double.class) || SimpleQuadrilateral.class.equals(Boolean.class) || SimpleQuadrilateral.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((SimpleQuadrilateral.class.equals(Integer.class) || SimpleQuadrilateral.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((SimpleQuadrilateral.class.equals(Float.class) || SimpleQuadrilateral.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (SimpleQuadrilateral.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (SimpleQuadrilateral.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(SimpleQuadrilateral.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'SimpleQuadrilateral'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'SimpleQuadrilateral'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Shape.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Shape.java index 53fb100975d..eba2e38da48 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Shape.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Shape.java @@ -49,10 +49,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -110,15 +112,30 @@ public class Shape extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for Shape. Possible values: Quadrilateral Triangle", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize Quadrilateral try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Quadrilateral.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Quadrilateral'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Quadrilateral.class.equals(Integer.class) || Quadrilateral.class.equals(Long.class) || Quadrilateral.class.equals(Float.class) || Quadrilateral.class.equals(Double.class) || Quadrilateral.class.equals(Boolean.class) || Quadrilateral.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Quadrilateral.class.equals(Integer.class) || Quadrilateral.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Quadrilateral.class.equals(Float.class) || Quadrilateral.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Quadrilateral.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Quadrilateral.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Quadrilateral.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Quadrilateral'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Quadrilateral'", e); @@ -126,12 +143,25 @@ public class Shape extends AbstractOpenApiSchema { // deserialize Triangle try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Triangle.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Triangle'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Triangle.class.equals(Integer.class) || Triangle.class.equals(Long.class) || Triangle.class.equals(Float.class) || Triangle.class.equals(Double.class) || Triangle.class.equals(Boolean.class) || Triangle.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Triangle.class.equals(Integer.class) || Triangle.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Triangle.class.equals(Float.class) || Triangle.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Triangle.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Triangle.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Triangle.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Triangle'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Triangle'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/ShapeOrNull.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/ShapeOrNull.java index 1a8d3c0a076..b951e2f4e9c 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/ShapeOrNull.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/ShapeOrNull.java @@ -49,10 +49,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -110,15 +112,31 @@ public class ShapeOrNull extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for ShapeOrNull. Possible values: Quadrilateral Triangle", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize Quadrilateral try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Quadrilateral.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Quadrilateral'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Quadrilateral.class.equals(Integer.class) || Quadrilateral.class.equals(Long.class) || Quadrilateral.class.equals(Float.class) || Quadrilateral.class.equals(Double.class) || Quadrilateral.class.equals(Boolean.class) || Quadrilateral.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Quadrilateral.class.equals(Integer.class) || Quadrilateral.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Quadrilateral.class.equals(Float.class) || Quadrilateral.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Quadrilateral.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Quadrilateral.class.equals(String.class) && token == JsonToken.VALUE_STRING); + attemptParsing |= (token == JsonToken.VALUE_NULL); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Quadrilateral.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Quadrilateral'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Quadrilateral'", e); @@ -126,12 +144,26 @@ public class ShapeOrNull extends AbstractOpenApiSchema { // deserialize Triangle try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(Triangle.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'Triangle'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (Triangle.class.equals(Integer.class) || Triangle.class.equals(Long.class) || Triangle.class.equals(Float.class) || Triangle.class.equals(Double.class) || Triangle.class.equals(Boolean.class) || Triangle.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((Triangle.class.equals(Integer.class) || Triangle.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((Triangle.class.equals(Float.class) || Triangle.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (Triangle.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (Triangle.class.equals(String.class) && token == JsonToken.VALUE_STRING); + attemptParsing |= (token == JsonToken.VALUE_NULL); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(Triangle.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'Triangle'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'Triangle'", e); diff --git a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Triangle.java b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Triangle.java index ab7f93d1a73..232fed5dc91 100644 --- a/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Triangle.java +++ b/samples/openapi3/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/Triangle.java @@ -50,10 +50,12 @@ import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -115,15 +117,30 @@ public class Triangle extends AbstractOpenApiSchema { log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for Triangle. Possible values: EquilateralTriangle IsoscelesTriangle ScaleneTriangle", discriminatorValue)); } + boolean typeCoercion = ctxt.isEnabled(MapperFeature.ALLOW_COERCION_OF_SCALARS); int match = 0; + JsonToken token = tree.traverse(jp.getCodec()).nextToken(); // deserialize EquilateralTriangle try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(EquilateralTriangle.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'EquilateralTriangle'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (EquilateralTriangle.class.equals(Integer.class) || EquilateralTriangle.class.equals(Long.class) || EquilateralTriangle.class.equals(Float.class) || EquilateralTriangle.class.equals(Double.class) || EquilateralTriangle.class.equals(Boolean.class) || EquilateralTriangle.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((EquilateralTriangle.class.equals(Integer.class) || EquilateralTriangle.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((EquilateralTriangle.class.equals(Float.class) || EquilateralTriangle.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (EquilateralTriangle.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (EquilateralTriangle.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(EquilateralTriangle.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'EquilateralTriangle'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'EquilateralTriangle'", e); @@ -131,12 +148,25 @@ public class Triangle extends AbstractOpenApiSchema { // deserialize IsoscelesTriangle try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(IsoscelesTriangle.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'IsoscelesTriangle'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (IsoscelesTriangle.class.equals(Integer.class) || IsoscelesTriangle.class.equals(Long.class) || IsoscelesTriangle.class.equals(Float.class) || IsoscelesTriangle.class.equals(Double.class) || IsoscelesTriangle.class.equals(Boolean.class) || IsoscelesTriangle.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((IsoscelesTriangle.class.equals(Integer.class) || IsoscelesTriangle.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((IsoscelesTriangle.class.equals(Float.class) || IsoscelesTriangle.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (IsoscelesTriangle.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (IsoscelesTriangle.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(IsoscelesTriangle.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'IsoscelesTriangle'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'IsoscelesTriangle'", e); @@ -144,12 +174,25 @@ public class Triangle extends AbstractOpenApiSchema { // deserialize ScaleneTriangle try { - deserialized = tree.traverse(jp.getCodec()).readValueAs(ScaleneTriangle.class); - // TODO: there is no validation against JSON schema constraints - // (min, max, enum, pattern...), this does not perform a strict JSON - // validation, which means the 'match' count may be higher than it should be. - match++; - log.log(Level.FINER, "Input data matches schema 'ScaleneTriangle'"); + boolean attemptParsing = true; + // ensure that we respect type coercion as set on the client ObjectMapper + if (ScaleneTriangle.class.equals(Integer.class) || ScaleneTriangle.class.equals(Long.class) || ScaleneTriangle.class.equals(Float.class) || ScaleneTriangle.class.equals(Double.class) || ScaleneTriangle.class.equals(Boolean.class) || ScaleneTriangle.class.equals(String.class)) { + attemptParsing = typeCoercion; + if (!attemptParsing) { + attemptParsing |= ((ScaleneTriangle.class.equals(Integer.class) || ScaleneTriangle.class.equals(Long.class)) && token == JsonToken.VALUE_NUMBER_INT); + attemptParsing |= ((ScaleneTriangle.class.equals(Float.class) || ScaleneTriangle.class.equals(Double.class)) && token == JsonToken.VALUE_NUMBER_FLOAT); + attemptParsing |= (ScaleneTriangle.class.equals(Boolean.class) && (token == JsonToken.VALUE_FALSE || token == JsonToken.VALUE_TRUE)); + attemptParsing |= (ScaleneTriangle.class.equals(String.class) && token == JsonToken.VALUE_STRING); + } + } + if (attemptParsing) { + deserialized = tree.traverse(jp.getCodec()).readValueAs(ScaleneTriangle.class); + // TODO: there is no validation against JSON schema constraints + // (min, max, enum, pattern...), this does not perform a strict JSON + // validation, which means the 'match' count may be higher than it should be. + match++; + log.log(Level.FINER, "Input data matches schema 'ScaleneTriangle'"); + } } catch (Exception e) { // deserialization failed, continue log.log(Level.FINER, "Input data does not match schema 'ScaleneTriangle'", e);