From 4f04d09aaab75e9af08d8eac151ead04b5606b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= <22489773+newtork@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:40:15 +0100 Subject: [PATCH] feat(openapi-generator): Allow for primitives in anyOf/oneOf component schema definitions (#681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Dümont --- datamodel/openapi/openapi-api-sample/pom.xml | 2 + .../datamodel/openapi/sample/model/AllOf.java | 45 +++- .../datamodel/openapi/sample/model/AnyOf.java | 45 +++- .../datamodel/openapi/sample/model/Fanta.java | 45 +++- .../openapi/sample/model/FantaFlavor.java | 85 +++++++ .../sample/model/FantaFlavorOneOf.java | 228 ++++++++++++++++++ .../src/main/resources/sodastore.yaml | 10 + .../sample/api/OneOfDeserializationTest.java | 12 +- .../GenerationConfigurationConverter.java | 67 ++++- .../generator/GeneratorCustomProperties.java | 48 ++++ .../oneof_interface.mustache | 36 +++ .../DataModelGeneratorIntegrationTest.java | 4 +- .../input/sodastore.yaml | 7 + .../output/test/AllOf.java | 39 ++- .../output/test/AnyOf.java | 39 ++- .../output/test/Fanta.java | 39 ++- .../output/test/FantaFlavor.java | 90 +++++++ .../output/test/OneOf.java | 1 + .../output/test/OneOfWithDiscriminator.java | 1 + .../OneOfWithDiscriminatorAndMapping.java | 1 + release_notes.md | 1 + 21 files changed, 827 insertions(+), 18 deletions(-) create mode 100644 datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavor.java create mode 100644 datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavorOneOf.java create mode 100644 datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GeneratorCustomProperties.java create mode 100644 datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/FantaFlavor.java diff --git a/datamodel/openapi/openapi-api-sample/pom.xml b/datamodel/openapi/openapi-api-sample/pom.xml index 32febda50..69af5bdd0 100644 --- a/datamodel/openapi/openapi-api-sample/pom.xml +++ b/datamodel/openapi/openapi-api-sample/pom.xml @@ -125,8 +125,10 @@ protected true + true true + true diff --git a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AllOf.java b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AllOf.java index 30d71c108..13849d1f0 100644 --- a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AllOf.java +++ b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AllOf.java @@ -45,6 +45,9 @@ public class AllOf @JsonProperty( "color" ) private String color; + @JsonProperty( "flavor" ) + private FantaFlavor flavor; + @JsonAnySetter @JsonAnyGetter private final Map cloudSdkCustomFields = new LinkedHashMap<>(); @@ -164,6 +167,42 @@ public void setColor( @Nullable final String color ) this.color = color; } + /** + * Set the flavor of this {@link AllOf} instance and return the same instance. + * + * @param flavor + * The flavor of this {@link AllOf} + * @return The same instance of this {@link AllOf} class + */ + @Nonnull + public AllOf flavor( @Nullable final FantaFlavor flavor ) + { + this.flavor = flavor; + return this; + } + + /** + * Get flavor + * + * @return flavor The flavor of this {@link AllOf} instance. + */ + @Nonnull + public FantaFlavor getFlavor() + { + return flavor; + } + + /** + * Set the flavor of this {@link AllOf} instance. + * + * @param flavor + * The flavor of this {@link AllOf} + */ + public void setFlavor( @Nullable final FantaFlavor flavor ) + { + this.flavor = flavor; + } + /** * Get the names of the unrecognizable properties of the {@link AllOf}. * @@ -223,13 +262,14 @@ public boolean equals( @Nullable final java.lang.Object o ) return Objects.equals(this.cloudSdkCustomFields, allOf.cloudSdkCustomFields) && Objects.equals(this.sodaType, allOf.sodaType) && Objects.equals(this.caffeine, allOf.caffeine) - && Objects.equals(this.color, allOf.color); + && Objects.equals(this.color, allOf.color) + && Objects.equals(this.flavor, allOf.flavor); } @Override public int hashCode() { - return Objects.hash(sodaType, caffeine, color, cloudSdkCustomFields); + return Objects.hash(sodaType, caffeine, color, flavor, cloudSdkCustomFields); } @Override @@ -241,6 +281,7 @@ public String toString() sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n"); sb.append(" caffeine: ").append(toIndentedString(caffeine)).append("\n"); sb.append(" color: ").append(toIndentedString(color)).append("\n"); + sb.append(" flavor: ").append(toIndentedString(flavor)).append("\n"); cloudSdkCustomFields .forEach(( k, v ) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n")); sb.append("}"); diff --git a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AnyOf.java b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AnyOf.java index b8e2fe850..b0b280f55 100644 --- a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AnyOf.java +++ b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/AnyOf.java @@ -45,6 +45,9 @@ public class AnyOf @JsonProperty( "color" ) private String color; + @JsonProperty( "flavor" ) + private FantaFlavor flavor; + @JsonAnySetter @JsonAnyGetter private final Map cloudSdkCustomFields = new LinkedHashMap<>(); @@ -164,6 +167,42 @@ public void setColor( @Nullable final String color ) this.color = color; } + /** + * Set the flavor of this {@link AnyOf} instance and return the same instance. + * + * @param flavor + * The flavor of this {@link AnyOf} + * @return The same instance of this {@link AnyOf} class + */ + @Nonnull + public AnyOf flavor( @Nullable final FantaFlavor flavor ) + { + this.flavor = flavor; + return this; + } + + /** + * Get flavor + * + * @return flavor The flavor of this {@link AnyOf} instance. + */ + @Nonnull + public FantaFlavor getFlavor() + { + return flavor; + } + + /** + * Set the flavor of this {@link AnyOf} instance. + * + * @param flavor + * The flavor of this {@link AnyOf} + */ + public void setFlavor( @Nullable final FantaFlavor flavor ) + { + this.flavor = flavor; + } + /** * Get the names of the unrecognizable properties of the {@link AnyOf}. * @@ -223,13 +262,14 @@ public boolean equals( @Nullable final java.lang.Object o ) return Objects.equals(this.cloudSdkCustomFields, anyOf.cloudSdkCustomFields) && Objects.equals(this.sodaType, anyOf.sodaType) && Objects.equals(this.caffeine, anyOf.caffeine) - && Objects.equals(this.color, anyOf.color); + && Objects.equals(this.color, anyOf.color) + && Objects.equals(this.flavor, anyOf.flavor); } @Override public int hashCode() { - return Objects.hash(sodaType, caffeine, color, cloudSdkCustomFields); + return Objects.hash(sodaType, caffeine, color, flavor, cloudSdkCustomFields); } @Override @@ -241,6 +281,7 @@ public String toString() sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n"); sb.append(" caffeine: ").append(toIndentedString(caffeine)).append("\n"); sb.append(" color: ").append(toIndentedString(color)).append("\n"); + sb.append(" flavor: ").append(toIndentedString(flavor)).append("\n"); cloudSdkCustomFields .forEach(( k, v ) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n")); sb.append("}"); diff --git a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/Fanta.java b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/Fanta.java index e706d20bb..92f882b43 100644 --- a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/Fanta.java +++ b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/Fanta.java @@ -42,6 +42,9 @@ public class Fanta implements OneOf, OneOfWithDiscriminator, OneOfWithDiscrimina @JsonProperty( "color" ) private String color; + @JsonProperty( "flavor" ) + private FantaFlavor flavor; + @JsonAnySetter @JsonAnyGetter private final Map cloudSdkCustomFields = new LinkedHashMap<>(); @@ -125,6 +128,42 @@ public void setColor( @Nullable final String color ) this.color = color; } + /** + * Set the flavor of this {@link Fanta} instance and return the same instance. + * + * @param flavor + * The flavor of this {@link Fanta} + * @return The same instance of this {@link Fanta} class + */ + @Nonnull + public Fanta flavor( @Nullable final FantaFlavor flavor ) + { + this.flavor = flavor; + return this; + } + + /** + * Get flavor + * + * @return flavor The flavor of this {@link Fanta} instance. + */ + @Nonnull + public FantaFlavor getFlavor() + { + return flavor; + } + + /** + * Set the flavor of this {@link Fanta} instance. + * + * @param flavor + * The flavor of this {@link Fanta} + */ + public void setFlavor( @Nullable final FantaFlavor flavor ) + { + this.flavor = flavor; + } + /** * Get the names of the unrecognizable properties of the {@link Fanta}. * @@ -183,13 +222,14 @@ public boolean equals( @Nullable final java.lang.Object o ) final Fanta fanta = (Fanta) o; return Objects.equals(this.cloudSdkCustomFields, fanta.cloudSdkCustomFields) && Objects.equals(this.sodaType, fanta.sodaType) - && Objects.equals(this.color, fanta.color); + && Objects.equals(this.color, fanta.color) + && Objects.equals(this.flavor, fanta.flavor); } @Override public int hashCode() { - return Objects.hash(sodaType, color, cloudSdkCustomFields); + return Objects.hash(sodaType, color, flavor, cloudSdkCustomFields); } @Override @@ -200,6 +240,7 @@ public String toString() sb.append("class Fanta {\n"); sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n"); sb.append(" color: ").append(toIndentedString(color)).append("\n"); + sb.append(" flavor: ").append(toIndentedString(flavor)).append("\n"); cloudSdkCustomFields .forEach(( k, v ) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n")); sb.append("}"); diff --git a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavor.java b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavor.java new file mode 100644 index 000000000..757b26ddf --- /dev/null +++ b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavor.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. + */ + +/* + * SodaStore API + * API for managing soda products and orders in SodaStore. + * + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package com.sap.cloud.sdk.datamodel.openapi.sample.model; + +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * FantaFlavor + */ +public interface FantaFlavor +{ + /** + * Helper class to create a Integer that implements {@link FantaFlavor}. + */ + record InnerInteger(@com.fasterxml.jackson.annotation.JsonValue @Nonnull Integer value) implements FantaFlavor {} + + /** + * Creator to enable deserialization of a Integer. + * + * @param val + * the value to use + * @return a new instance of {@link InnerInteger}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static InnerInteger create( @Nonnull final Integer val ) + { + return new InnerInteger(val); + } + + /** + * Helper class to create a FantaFlavorOneOf that implements {@link FantaFlavor}. + */ + record InnerFantaFlavorOneOf(@com.fasterxml.jackson.annotation.JsonValue @Nonnull FantaFlavorOneOf value) implements FantaFlavor {} + + /** + * Creator to enable deserialization of a FantaFlavorOneOf. + * + * @param val + * the value to use + * @return a new instance of {@link InnerFantaFlavorOneOf}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static InnerFantaFlavorOneOf create( @Nonnull final FantaFlavorOneOf val ) + { + return new InnerFantaFlavorOneOf(val); + } + + /** + * Helper class to create a String that implements {@link FantaFlavor}. + */ + record InnerString(@com.fasterxml.jackson.annotation.JsonValue @Nonnull String value) implements FantaFlavor {} + + /** + * Creator to enable deserialization of a String. + * + * @param val + * the value to use + * @return a new instance of {@link InnerString}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static InnerString create( @Nonnull final String val ) + { + return new InnerString(val); + } + +} diff --git a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavorOneOf.java b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavorOneOf.java new file mode 100644 index 000000000..af4b7cb22 --- /dev/null +++ b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/model/FantaFlavorOneOf.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. + */ + +/* + * SodaStore API + * API for managing soda products and orders in SodaStore. + * + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package com.sap.cloud.sdk.datamodel.openapi.sample.model; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Set; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * FantaFlavorOneOf + */ +// CHECKSTYLE:OFF +public class FantaFlavorOneOf +// CHECKSTYLE:ON +{ + @JsonProperty( "intensity" ) + private Integer intensity; + + @JsonProperty( "nuance" ) + private String nuance; + + @JsonAnySetter + @JsonAnyGetter + private final Map cloudSdkCustomFields = new LinkedHashMap<>(); + + /** + * Default constructor for FantaFlavorOneOf. + */ + protected FantaFlavorOneOf() + { + } + + /** + * Set the intensity of this {@link FantaFlavorOneOf} instance and return the same instance. + * + * @param intensity + * The intensity of this {@link FantaFlavorOneOf} + * @return The same instance of this {@link FantaFlavorOneOf} class + */ + @Nonnull + public FantaFlavorOneOf intensity( @Nullable final Integer intensity ) + { + this.intensity = intensity; + return this; + } + + /** + * Get intensity + * + * @return intensity The intensity of this {@link FantaFlavorOneOf} instance. + */ + @Nonnull + public Integer getIntensity() + { + return intensity; + } + + /** + * Set the intensity of this {@link FantaFlavorOneOf} instance. + * + * @param intensity + * The intensity of this {@link FantaFlavorOneOf} + */ + public void setIntensity( @Nullable final Integer intensity ) + { + this.intensity = intensity; + } + + /** + * Set the nuance of this {@link FantaFlavorOneOf} instance and return the same instance. + * + * @param nuance + * The nuance of this {@link FantaFlavorOneOf} + * @return The same instance of this {@link FantaFlavorOneOf} class + */ + @Nonnull + public FantaFlavorOneOf nuance( @Nullable final String nuance ) + { + this.nuance = nuance; + return this; + } + + /** + * Get nuance + * + * @return nuance The nuance of this {@link FantaFlavorOneOf} instance. + */ + @Nonnull + public String getNuance() + { + return nuance; + } + + /** + * Set the nuance of this {@link FantaFlavorOneOf} instance. + * + * @param nuance + * The nuance of this {@link FantaFlavorOneOf} + */ + public void setNuance( @Nullable final String nuance ) + { + this.nuance = nuance; + } + + /** + * Get the names of the unrecognizable properties of the {@link FantaFlavorOneOf}. + * + * @return The set of properties names + */ + @JsonIgnore + @Nonnull + public Set getCustomFieldNames() + { + return cloudSdkCustomFields.keySet(); + } + + /** + * Get the value of an unrecognizable property of this {@link FantaFlavorOneOf} instance. + * + * @param name + * The name of the property + * @return The value of the property + * @throws NoSuchElementException + * If no property with the given name could be found. + */ + @Nullable + public Object getCustomField( @Nonnull final String name ) + throws NoSuchElementException + { + if( !cloudSdkCustomFields.containsKey(name) ) { + throw new NoSuchElementException("FantaFlavorOneOf has no field with name '" + name + "'."); + } + return cloudSdkCustomFields.get(name); + } + + /** + * Set an unrecognizable property of this {@link FantaFlavorOneOf} instance. If the map previously contained a + * mapping for the key, the old value is replaced by the specified value. + * + * @param customFieldName + * The name of the property + * @param customFieldValue + * The value of the property + */ + @JsonIgnore + public void setCustomField( @Nonnull String customFieldName, @Nullable Object customFieldValue ) + { + cloudSdkCustomFields.put(customFieldName, customFieldValue); + } + + @Override + public boolean equals( @Nullable final java.lang.Object o ) + { + if( this == o ) { + return true; + } + if( o == null || getClass() != o.getClass() ) { + return false; + } + final FantaFlavorOneOf fantaFlavorOneOf = (FantaFlavorOneOf) o; + return Objects.equals(this.cloudSdkCustomFields, fantaFlavorOneOf.cloudSdkCustomFields) + && Objects.equals(this.intensity, fantaFlavorOneOf.intensity) + && Objects.equals(this.nuance, fantaFlavorOneOf.nuance); + } + + @Override + public int hashCode() + { + return Objects.hash(intensity, nuance, cloudSdkCustomFields); + } + + @Override + @Nonnull + public String toString() + { + final StringBuilder sb = new StringBuilder(); + sb.append("class FantaFlavorOneOf {\n"); + sb.append(" intensity: ").append(toIndentedString(intensity)).append("\n"); + sb.append(" nuance: ").append(toIndentedString(nuance)).append("\n"); + cloudSdkCustomFields + .forEach(( k, v ) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).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( final java.lang.Object o ) + { + if( o == null ) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + /** + * Create a new {@link FantaFlavorOneOf} instance. No arguments are required. + */ + public static FantaFlavorOneOf create() + { + return new FantaFlavorOneOf(); + } + +} diff --git a/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml b/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml index 3b0223201..01aac4c59 100644 --- a/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml +++ b/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml @@ -161,6 +161,16 @@ components: type: string color: type: string + flavor: + oneOf: + - type: string + - type: integer + - type: object + properties: + intensity: + type: integer + nuance: + type: string paths: /sodas: get: diff --git a/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/OneOfDeserializationTest.java b/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/OneOfDeserializationTest.java index 1e80cf85b..c98492763 100644 --- a/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/OneOfDeserializationTest.java +++ b/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/OneOfDeserializationTest.java @@ -19,6 +19,8 @@ import com.sap.cloud.sdk.datamodel.openapi.sample.model.Bar; import com.sap.cloud.sdk.datamodel.openapi.sample.model.Cola; import com.sap.cloud.sdk.datamodel.openapi.sample.model.Fanta; +import com.sap.cloud.sdk.datamodel.openapi.sample.model.FantaFlavor; +import com.sap.cloud.sdk.datamodel.openapi.sample.model.FantaFlavorOneOf; import com.sap.cloud.sdk.datamodel.openapi.sample.model.Foo; import com.sap.cloud.sdk.datamodel.openapi.sample.model.OneOf; import com.sap.cloud.sdk.datamodel.openapi.sample.model.OneOfWithDiscriminator; @@ -30,7 +32,12 @@ class OneOfDeserializationTest private static final ObjectMapper objectMapper = newDefaultObjectMapper(); private static final Cola COLA_OBJECT = Cola.create().caffeine(true).sodaType("Cola"); - private static final Fanta FANTA_OBJECT = Fanta.create().color("orange").sodaType("Fanta"); + private static final Fanta FANTA_OBJECT = + Fanta + .create() + .color("orange") + .sodaType("Fanta") + .flavor(new FantaFlavor.InnerFantaFlavorOneOf(FantaFlavorOneOf.create().intensity(3).nuance("wood"))); private static final String COLA_JSON = """ { "sodaType": "Cola", @@ -39,7 +46,8 @@ class OneOfDeserializationTest private static final String FANTA_JSON = """ { "sodaType": "Fanta", - "color": "orange" + "color": "orange", + "flavor": {"intensity":3,"nuance":"wood"} }"""; private static final String UNKNOWN_JSON = """ { diff --git a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java index 9ffe19c30..4d4656e6f 100644 --- a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java +++ b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java @@ -1,11 +1,15 @@ package com.sap.cloud.sdk.datamodel.openapi.generator; +import static com.sap.cloud.sdk.datamodel.openapi.generator.GeneratorCustomProperties.USE_ONE_OF_CREATORS; + import java.nio.file.Path; import java.nio.file.Paths; import java.time.Year; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.Nonnull; @@ -57,7 +61,7 @@ static ClientOptInput convertGenerationConfiguration( setGlobalSettings(generationConfiguration); final var inputSpecFile = inputSpec.toString(); - final var config = createCodegenConfig(); + final var config = createCodegenConfig(generationConfiguration); config.setOutputDir(generationConfiguration.getOutputDirectory()); config.setLibrary(LIBRARY_NAME); config.setApiPackage(generationConfiguration.getApiPackage()); @@ -71,8 +75,9 @@ static ClientOptInput convertGenerationConfiguration( return clientOptInput; } - private static JavaClientCodegen createCodegenConfig() + private static JavaClientCodegen createCodegenConfig( @Nonnull final GenerationConfiguration config ) { + final var primitives = Set.of("String", "Integer", "Long", "Double", "Float", "Byte"); return new JavaClientCodegen() { // Custom processor to inject "x-return-nullable" extension @@ -92,6 +97,64 @@ public OperationsMap postProcessOperationsWithModels( return super.postProcessOperationsWithModels(ops, allModels); } + @SuppressWarnings( { "rawtypes", "RedundantSuppression" } ) + @Override + protected void updateModelForComposedSchema( + @Nonnull final CodegenModel m, + @Nonnull final Schema schema, + @Nonnull final Map allDefinitions ) + { + super.updateModelForComposedSchema(m, schema, allDefinitions); + + if( USE_ONE_OF_CREATORS.isEnabled(config) ) { + useCreatorsForInterfaceSubtypes(m); + } + } + + /** + * Use JsonCreator for interface sub-types in case there are any primitives. + * + * @param m + * The model to update. + */ + private void useCreatorsForInterfaceSubtypes( @Nonnull final CodegenModel m ) + { + if( m.discriminator != null ) { + return; + } + boolean useCreators = false; + for( final Set candidates : List.of(m.anyOf, m.oneOf) ) { + int nonPrimitives = 0; + final var candidatesSingle = new HashSet(); + final var candidatesMultiple = new HashSet(); + + for( final String candidate : candidates ) { + if( candidate.startsWith("List<") ) { + final var c1 = candidate.substring(5, candidate.length() - 1); + candidatesMultiple.add(c1); + useCreators = true; + } else { + candidatesSingle.add(candidate); + useCreators |= primitives.contains(candidate); + if( !primitives.contains(candidate) ) { + nonPrimitives++; + } + } + } + if( useCreators ) { + if( nonPrimitives > 1 ) { + final var msg = + "Generating interface with mixed multiple non-primitive and primitive sub-types: {}. Deserialization may not work."; + log.warn(msg, m.name); + } + candidates.clear(); + final var monads = Map.of("single", candidatesSingle, "multiple", candidatesMultiple); + m.vendorExtensions.put("x-monads", monads); + m.vendorExtensions.put("x-is-one-of-interface", true); // enforce template usage + } + } + } + @SuppressWarnings( { "rawtypes", "RedundantSuppression" } ) @Override protected void updateModelForObject( @Nonnull final CodegenModel m, @Nonnull final Schema schema ) diff --git a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GeneratorCustomProperties.java b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GeneratorCustomProperties.java new file mode 100644 index 000000000..84929fb5d --- /dev/null +++ b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GeneratorCustomProperties.java @@ -0,0 +1,48 @@ +package com.sap.cloud.sdk.datamodel.openapi.generator; + +import javax.annotation.Nonnull; + +import com.sap.cloud.sdk.datamodel.openapi.generator.model.GenerationConfiguration; + +import lombok.RequiredArgsConstructor; + +/** + * Optional feature toggles, may be used internally only. + */ +@RequiredArgsConstructor +enum GeneratorCustomProperties +{ + /** + * Use JsonCreator instead of sub-type deduction for oneOf and anyOf schemas. + */ + USE_ONE_OF_CREATORS("useOneOfCreators", "false"); + + private final String key; + private final String defaultValue; + + /** + * Check if the feature is enabled. + * + * @param config + * The generation configuration. + * @return True if the feature is enabled, false otherwise. + */ + public boolean isEnabled( @Nonnull final GenerationConfiguration config ) + { + final var value = getValue(config); + return !value.isEmpty() && !"false".equalsIgnoreCase(value.trim()); + } + + /** + * Get the value of the feature. + * + * @param config + * The generation configuration. + * @return The value of the feature. + */ + @Nonnull + public String getValue( @Nonnull final GenerationConfiguration config ) + { + return config.getAdditionalProperties().getOrDefault(key, defaultValue); + } +} diff --git a/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/oneof_interface.mustache b/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/oneof_interface.mustache index f84cb4603..b88e6d5a1 100644 --- a/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/oneof_interface.mustache +++ b/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/oneof_interface.mustache @@ -4,9 +4,45 @@ */{{#isDeprecated}} @Deprecated{{/isDeprecated}}{{^isReleased}} @Beta{{/isReleased}} +{{^model.vendorExtensions.x-monads}} {{>additionalOneOfTypeAnnotations}}{{>typeInfoAnnotation}}{{>xmlAnnotation}} +{{/model.vendorExtensions.x-monads}} public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { {{#discriminator}} Object {{propertyGetter}}(); {{/discriminator}} +{{#model.vendorExtensions.x-monads.single}} + /** + * Helper class to create a {{.}} that implements {@link {{classname}}}. + */ + record Inner{{.}}(@com.fasterxml.jackson.annotation.JsonValue @Nonnull {{.}} value) implements {{classname}} {} + + /** + * Creator to enable deserialization of a {{.}}. + * + * @param val the value to use + * @return a new instance of {@link Inner{{.}}}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static Inner{{.}} create( @Nonnull final {{.}} val) { return new Inner{{.}}(val); } + +{{/model.vendorExtensions.x-monads.single}} +{{#model.vendorExtensions.x-monads.multiple}} + /** + * Helper class to create a list of {{.}} that implements {@link {{classname}}}. + */ + record Inner{{.}}s(@com.fasterxml.jackson.annotation.JsonValue @Nonnull List<{{.}}> values) implements {{classname}} {} + + /** + * Creator to enable deserialization of a list of {{.}}. + * + * @param val the value to use + * @return a new instance of {@link Inner{{.}}s}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static Inner{{.}}s create( @Nonnull final List<{{.}}> val) { return new Inner{{.}}s(val); } + +{{/model.vendorExtensions.x-monads.multiple}} } diff --git a/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorIntegrationTest.java b/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorIntegrationTest.java index 0d2df3a24..2152052f8 100644 --- a/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorIntegrationTest.java +++ b/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorIntegrationTest.java @@ -83,8 +83,8 @@ private enum TestCase ApiMaturity.BETA, true, true, - 8, - Map.of("useOneOfInterfaces", "true")), + 9, + Map.of("useOneOfInterfaces", "true", "useOneOfCreators", "true")), INPUT_SPEC_WITH_BUILDER( "input-spec-with-builder", "sodastore.JSON", diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/input/sodastore.yaml b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/input/sodastore.yaml index e7a169e45..19b65ab45 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/input/sodastore.yaml +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/input/sodastore.yaml @@ -56,3 +56,10 @@ components: properties: sodaType: type: string + flavor: + oneOf: + - type: string + - $ref: '#/components/schemas/Cola' + - type: array + items: + type: string diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AllOf.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AllOf.java index 9bf816352..0e3c00d74 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AllOf.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AllOf.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; +import test.FantaFlavor; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -45,6 +46,9 @@ public class AllOf @JsonProperty("sodaType") private String sodaType; + @JsonProperty("flavor") + private FantaFlavor flavor; + @JsonAnySetter @JsonAnyGetter private final Map cloudSdkCustomFields = new LinkedHashMap<>(); @@ -78,6 +82,35 @@ public void setSodaType( @Nullable final String sodaType) { this.sodaType = sodaType; } + /** + * Set the flavor of this {@link AllOf} instance and return the same instance. + * + * @param flavor The flavor of this {@link AllOf} + * @return The same instance of this {@link AllOf} class + */ + @Nonnull public AllOf flavor( @Nullable final FantaFlavor flavor) { + this.flavor = flavor; + return this; + } + + /** + * Get flavor + * @return flavor The flavor of this {@link AllOf} instance. + */ + @Nonnull + public FantaFlavor getFlavor() { + return flavor; + } + + /** + * Set the flavor of this {@link AllOf} instance. + * + * @param flavor The flavor of this {@link AllOf} + */ + public void setFlavor( @Nullable final FantaFlavor flavor) { + this.flavor = flavor; + } + /** * Get the names of the unrecognizable properties of the {@link AllOf}. * @return The set of properties names @@ -125,12 +158,13 @@ public boolean equals(@Nullable final java.lang.Object o) { } final AllOf allOf = (AllOf) o; return Objects.equals(this.cloudSdkCustomFields, allOf.cloudSdkCustomFields) && - Objects.equals(this.sodaType, allOf.sodaType); + Objects.equals(this.sodaType, allOf.sodaType) && + Objects.equals(this.flavor, allOf.flavor); } @Override public int hashCode() { - return Objects.hash(sodaType, cloudSdkCustomFields); + return Objects.hash(sodaType, flavor, cloudSdkCustomFields); } @Override @@ -138,6 +172,7 @@ public int hashCode() { final StringBuilder sb = new StringBuilder(); sb.append("class AllOf {\n"); sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n"); + sb.append(" flavor: ").append(toIndentedString(flavor)).append("\n"); cloudSdkCustomFields.forEach((k,v) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n")); sb.append("}"); return sb.toString(); diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AnyOf.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AnyOf.java index 2eb5c01ce..6b46264d6 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AnyOf.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/AnyOf.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import test.Cola; import test.Fanta; +import test.FantaFlavor; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -47,6 +48,9 @@ public class AnyOf @JsonProperty("sodaType") private String sodaType; + @JsonProperty("flavor") + private FantaFlavor flavor; + @JsonAnySetter @JsonAnyGetter private final Map cloudSdkCustomFields = new LinkedHashMap<>(); @@ -80,6 +84,35 @@ public void setSodaType( @Nullable final String sodaType) { this.sodaType = sodaType; } + /** + * Set the flavor of this {@link AnyOf} instance and return the same instance. + * + * @param flavor The flavor of this {@link AnyOf} + * @return The same instance of this {@link AnyOf} class + */ + @Nonnull public AnyOf flavor( @Nullable final FantaFlavor flavor) { + this.flavor = flavor; + return this; + } + + /** + * Get flavor + * @return flavor The flavor of this {@link AnyOf} instance. + */ + @Nonnull + public FantaFlavor getFlavor() { + return flavor; + } + + /** + * Set the flavor of this {@link AnyOf} instance. + * + * @param flavor The flavor of this {@link AnyOf} + */ + public void setFlavor( @Nullable final FantaFlavor flavor) { + this.flavor = flavor; + } + /** * Get the names of the unrecognizable properties of the {@link AnyOf}. * @return The set of properties names @@ -127,12 +160,13 @@ public boolean equals(@Nullable final java.lang.Object o) { } final AnyOf anyOf = (AnyOf) o; return Objects.equals(this.cloudSdkCustomFields, anyOf.cloudSdkCustomFields) && - Objects.equals(this.sodaType, anyOf.sodaType); + Objects.equals(this.sodaType, anyOf.sodaType) && + Objects.equals(this.flavor, anyOf.flavor); } @Override public int hashCode() { - return Objects.hash(sodaType, cloudSdkCustomFields); + return Objects.hash(sodaType, flavor, cloudSdkCustomFields); } @Override @@ -140,6 +174,7 @@ public int hashCode() { final StringBuilder sb = new StringBuilder(); sb.append("class AnyOf {\n"); sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n"); + sb.append(" flavor: ").append(toIndentedString(flavor)).append("\n"); cloudSdkCustomFields.forEach((k,v) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n")); sb.append("}"); return sb.toString(); diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/Fanta.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/Fanta.java index 82fcbdce1..ddc9f87a0 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/Fanta.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/Fanta.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; +import test.FantaFlavor; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -48,6 +49,9 @@ public class Fanta implements OneOf, OneOfWithDiscriminator, OneOfWithDiscrimina @JsonProperty("sodaType") private String sodaType; + @JsonProperty("flavor") + private FantaFlavor flavor; + @JsonAnySetter @JsonAnyGetter private final Map cloudSdkCustomFields = new LinkedHashMap<>(); @@ -81,6 +85,35 @@ public void setSodaType( @Nullable final String sodaType) { this.sodaType = sodaType; } + /** + * Set the flavor of this {@link Fanta} instance and return the same instance. + * + * @param flavor The flavor of this {@link Fanta} + * @return The same instance of this {@link Fanta} class + */ + @Nonnull public Fanta flavor( @Nullable final FantaFlavor flavor) { + this.flavor = flavor; + return this; + } + + /** + * Get flavor + * @return flavor The flavor of this {@link Fanta} instance. + */ + @Nonnull + public FantaFlavor getFlavor() { + return flavor; + } + + /** + * Set the flavor of this {@link Fanta} instance. + * + * @param flavor The flavor of this {@link Fanta} + */ + public void setFlavor( @Nullable final FantaFlavor flavor) { + this.flavor = flavor; + } + /** * Get the names of the unrecognizable properties of the {@link Fanta}. * @return The set of properties names @@ -128,12 +161,13 @@ public boolean equals(@Nullable final java.lang.Object o) { } final Fanta fanta = (Fanta) o; return Objects.equals(this.cloudSdkCustomFields, fanta.cloudSdkCustomFields) && - Objects.equals(this.sodaType, fanta.sodaType); + Objects.equals(this.sodaType, fanta.sodaType) && + Objects.equals(this.flavor, fanta.flavor); } @Override public int hashCode() { - return Objects.hash(sodaType, cloudSdkCustomFields); + return Objects.hash(sodaType, flavor, cloudSdkCustomFields); } @Override @@ -141,6 +175,7 @@ public int hashCode() { final StringBuilder sb = new StringBuilder(); sb.append("class Fanta {\n"); sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n"); + sb.append(" flavor: ").append(toIndentedString(flavor)).append("\n"); cloudSdkCustomFields.forEach((k,v) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n")); sb.append("}"); return sb.toString(); diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/FantaFlavor.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/FantaFlavor.java new file mode 100644 index 000000000..a2a8010fa --- /dev/null +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/FantaFlavor.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. + */ + +/* + * Soda Store API + * API for managing sodas in a soda store + * + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package test; + +import java.util.Objects; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.List; +import test.Cola; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * FantaFlavor + */ +@Beta +public interface FantaFlavor { + /** + * Helper class to create a Cola that implements {@link FantaFlavor}. + */ + record InnerCola(@com.fasterxml.jackson.annotation.JsonValue @Nonnull Cola value) implements FantaFlavor {} + + /** + * Creator to enable deserialization of a Cola. + * + * @param val the value to use + * @return a new instance of {@link InnerCola}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static InnerCola create( @Nonnull final Cola val) { return new InnerCola(val); } + + /** + * Helper class to create a String that implements {@link FantaFlavor}. + */ + record InnerString(@com.fasterxml.jackson.annotation.JsonValue @Nonnull String value) implements FantaFlavor {} + + /** + * Creator to enable deserialization of a String. + * + * @param val the value to use + * @return a new instance of {@link InnerString}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static InnerString create( @Nonnull final String val) { return new InnerString(val); } + + /** + * Helper class to create a list of String that implements {@link FantaFlavor}. + */ + record InnerStrings(@com.fasterxml.jackson.annotation.JsonValue @Nonnull List values) implements FantaFlavor {} + + /** + * Creator to enable deserialization of a list of String. + * + * @param val the value to use + * @return a new instance of {@link InnerStrings}. + */ + @com.fasterxml.jackson.annotation.JsonCreator + @Nonnull + static InnerStrings create( @Nonnull final List val) { return new InnerStrings(val); } + +} + diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOf.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOf.java index 3cabb6b93..c3349a809 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOf.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOf.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import test.Cola; import test.Fanta; +import test.FantaFlavor; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminator.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminator.java index 3f10ade93..72fba9625 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminator.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminator.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import test.Cola; import test.Fanta; +import test.FantaFlavor; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminatorAndMapping.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminatorAndMapping.java index 58c713ff1..b2ff80e18 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminatorAndMapping.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorIntegrationTest/oneof-interfaces-enabled/output/test/OneOfWithDiscriminatorAndMapping.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import test.Cola; import test.Fanta; +import test.FantaFlavor; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/release_notes.md b/release_notes.md index 56fe3693f..206f3727a 100644 --- a/release_notes.md +++ b/release_notes.md @@ -23,3 +23,4 @@ - Fix non-compilable code using OpenAPI generator with schema definitions having `additionalProperties: true`. Previously they would result in model classes extending `HashMap`, which disabled proper deserialization and serialization. +