From 205514c4559afa6a23820ab79fe118a9a7299ccd Mon Sep 17 00:00:00 2001 From: Slavek Kabrda Date: Mon, 25 May 2020 09:17:52 +0200 Subject: [PATCH] [Java][jersey2] Make (de)serialization work for oneOf models, add convenience and comparison methods (#6323) --- .../jersey2/AbstractOpenApiSchema.mustache | 44 +++++++++++++++++ .../libraries/jersey2/oneof_model.mustache | 47 +++++++++++++++++++ .../client/model/AbstractOpenApiSchema.java | 44 +++++++++++++++++ .../client/model/AbstractOpenApiSchema.java | 44 +++++++++++++++++ 4 files changed, 179 insertions(+) diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/AbstractOpenApiSchema.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/AbstractOpenApiSchema.mustache index c924650e6c0..f928aad9d75 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/AbstractOpenApiSchema.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/jersey2/AbstractOpenApiSchema.mustache @@ -3,10 +3,13 @@ package {{invokerPackage}}.model; import {{invokerPackage}}.ApiException; +import java.util.Objects; import java.lang.reflect.Type; import java.util.Map; import javax.ws.rs.core.GenericType; +import com.fasterxml.jackson.annotation.JsonValue; + /** * Abstract class for oneOf,anyOf schemas defined in OpenAPI spec */ @@ -39,6 +42,7 @@ public abstract class AbstractOpenApiSchema { * * @return an instance of the actual schema/object */ + @JsonValue public Object getActualInstance() {return instance;} /*** @@ -57,6 +61,46 @@ public abstract class AbstractOpenApiSchema { return schemaType; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ").append(getClass()).append(" {\n"); + sb.append(" instance: ").append(toIndentedString(instance)).append("\n"); + sb.append(" isNullable: ").append(toIndentedString(isNullable)).append("\n"); + sb.append(" schemaType: ").append(toIndentedString(schemaType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractOpenApiSchema a = (AbstractOpenApiSchema) o; + return Objects.equals(this.instance, a.instance) && + Objects.equals(this.isNullable, a.isNullable) && + Objects.equals(this.schemaType, a.schemaType); + } + + @Override + public int hashCode() { + return Objects.hash(instance, isNullable, schemaType); + } + /*** * Is nullalble * 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 ffd739dfdd8..a2a9b045814 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 @@ -1,11 +1,51 @@ import javax.ws.rs.core.GenericType; import javax.ws.rs.core.Response; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>xmlAnnotation}} +@JsonDeserialize(using={{classname}}.{{classname}}Deserializer.class) public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-implements}}, {{{.}}}{{/vendorExtensions.x-implements}} { + public static class {{classname}}Deserializer extends StdDeserializer<{{classname}}> { + public {{classname}}Deserializer() { + this({{classname}}.class); + } + + public {{classname}}Deserializer(Class vc) { + super(vc); + } + + @Override + public {{classname}} deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + JsonNode tree = jp.readValueAsTree(); + + int match = 0; + Object deserialized = null; + {{#oneOf}} + try { + deserialized = tree.traverse(jp.getCodec()).readValueAs({{{.}}}.class); + match++; + } catch (Exception e) { + // deserialization failed, continue + } + {{/oneOf}} + if (match == 1) { + {{classname}} ret = new {{classname}}(); + ret.setActualInstance(deserialized); + return ret; + } + throw new IOException(String.format("Failed deserialization for {{classname}}: %d classes match result, expected 1", match)); + } + } // store a list of schema names defined in oneOf public final static Map schemas = new HashMap(); @@ -14,6 +54,13 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im super("oneOf", {{#isNullable}}Boolean.TRUE{{/isNullable}}{{^isNullable}}Boolean.FALSE{{/isNullable}}); } + {{#oneOf}} + public {{classname}}({{{.}}} o) { + super("oneOf", {{#isNullable}}Boolean.TRUE{{/isNullable}}{{^isNullable}}Boolean.FALSE{{/isNullable}}); + setActualInstance(o); + } + {{/oneOf}} + static { {{#oneOf}} schemas.put("{{{.}}}", new GenericType<{{{.}}}>() { diff --git a/samples/client/petstore/java/jersey2-java7/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java b/samples/client/petstore/java/jersey2-java7/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java index 3e95f2d66f7..89269434446 100644 --- a/samples/client/petstore/java/jersey2-java7/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java +++ b/samples/client/petstore/java/jersey2-java7/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java @@ -14,10 +14,13 @@ package org.openapitools.client.model; import org.openapitools.client.ApiException; +import java.util.Objects; import java.lang.reflect.Type; import java.util.Map; import javax.ws.rs.core.GenericType; +import com.fasterxml.jackson.annotation.JsonValue; + /** * Abstract class for oneOf,anyOf schemas defined in OpenAPI spec */ @@ -50,6 +53,7 @@ public abstract class AbstractOpenApiSchema { * * @return an instance of the actual schema/object */ + @JsonValue public Object getActualInstance() {return instance;} /*** @@ -68,6 +72,46 @@ public abstract class AbstractOpenApiSchema { return schemaType; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ").append(getClass()).append(" {\n"); + sb.append(" instance: ").append(toIndentedString(instance)).append("\n"); + sb.append(" isNullable: ").append(toIndentedString(isNullable)).append("\n"); + sb.append(" schemaType: ").append(toIndentedString(schemaType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractOpenApiSchema a = (AbstractOpenApiSchema) o; + return Objects.equals(this.instance, a.instance) && + Objects.equals(this.isNullable, a.isNullable) && + Objects.equals(this.schemaType, a.schemaType); + } + + @Override + public int hashCode() { + return Objects.hash(instance, isNullable, schemaType); + } + /*** * Is nullalble * diff --git a/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java b/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java index 3e95f2d66f7..89269434446 100644 --- a/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java +++ b/samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java @@ -14,10 +14,13 @@ package org.openapitools.client.model; import org.openapitools.client.ApiException; +import java.util.Objects; import java.lang.reflect.Type; import java.util.Map; import javax.ws.rs.core.GenericType; +import com.fasterxml.jackson.annotation.JsonValue; + /** * Abstract class for oneOf,anyOf schemas defined in OpenAPI spec */ @@ -50,6 +53,7 @@ public abstract class AbstractOpenApiSchema { * * @return an instance of the actual schema/object */ + @JsonValue public Object getActualInstance() {return instance;} /*** @@ -68,6 +72,46 @@ public abstract class AbstractOpenApiSchema { return schemaType; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ").append(getClass()).append(" {\n"); + sb.append(" instance: ").append(toIndentedString(instance)).append("\n"); + sb.append(" isNullable: ").append(toIndentedString(isNullable)).append("\n"); + sb.append(" schemaType: ").append(toIndentedString(schemaType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractOpenApiSchema a = (AbstractOpenApiSchema) o; + return Objects.equals(this.instance, a.instance) && + Objects.equals(this.isNullable, a.isNullable) && + Objects.equals(this.schemaType, a.schemaType); + } + + @Override + public int hashCode() { + return Objects.hash(instance, isNullable, schemaType); + } + /*** * Is nullalble *