diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 4708e10e4915..22b3dfb31206 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -35,8 +35,15 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.stream.Collectors; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; import org.apache.commons.lang3.tuple.Pair; import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CodegenConstants; @@ -64,6 +71,7 @@ import org.openapitools.codegen.model.ModelsMap; import org.openapitools.codegen.templating.mustache.SplitStringLambda; import org.openapitools.codegen.templating.mustache.TrimWhitespaceLambda; +import org.openapitools.codegen.utils.ModelUtils; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -140,6 +148,8 @@ public SpringCodegen() { modelPackage = "org.openapitools.model"; invokerPackage = "org.openapitools.api"; artifactId = "openapi-spring"; + useOneOfInterfaces = true; + addOneOfInterfaceImports = true; // clioOptions default redefinition need to be updated updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage()); @@ -569,7 +579,11 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera @Override public void preprocessOpenAPI(OpenAPI openAPI) { - super.preprocessOpenAPI(openAPI); + if (openAPI.getComponents() != null) { + preprocessInlineOneOf(openAPI); + super.preprocessOpenAPI(openAPI); + } + /* * TODO the following logic should not need anymore in OAS 3.0 if * ("/".equals(swagger.getBasePath())) { swagger.setBasePath(""); } @@ -953,6 +967,99 @@ public void setUseOptional(boolean useOptional) { } @Override + public void addImportsToOneOfInterface(List> imports) { + if (additionalProperties.containsKey(JACKSON)) { + for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) { + Map oneImport = new HashMap<>(); + oneImport.put("import", importMapping.get(i)); + if (!imports.contains(oneImport)) { + imports.add(oneImport); + } + } + } + } + + @Override + public Map postProcessAllModels(Map objs) { + Map postProcessedModels = super.postProcessAllModels(objs); + + for (Map.Entry modelsEntry : objs.entrySet()) { + ModelsMap modelsMap = modelsEntry.getValue(); + List models = modelsMap.getModels(); + for (ModelMap modelMap : models) { + CodegenModel cm = (CodegenModel) modelMap.get("model"); + if (cm.oneOf.size() > 0) { + cm.vendorExtensions.put("x-deduction", true); + cm.vendorExtensions.put("x-deduction-model-names", cm.oneOf.toArray()); + } + } + } + + return postProcessedModels; + } + + private void preprocessInlineOneOf(OpenAPI openAPI) { + if (openAPI != null) { + if (openAPI.getPaths() != null) { + for (Map.Entry openAPIGetPathsEntry : openAPI.getPaths().entrySet()) { + String pathname = openAPIGetPathsEntry.getKey(); + PathItem path = openAPIGetPathsEntry.getValue(); + if (path.readOperations() == null) { + continue; + } + for (Operation operation : path.readOperations()) { + boolean hasBodyParameter = hasBodyParameter(openAPI, operation); + + // OpenAPI parser do not add Inline One Of models in Operations to Components/Schemas + if (hasBodyParameter(openAPI, operation)) { + Optional.ofNullable(operation.getRequestBody()) + .map(RequestBody::getContent) + .ifPresent(this::repairInlineOneOf); + } + if (operation.getResponses() != null) { + operation.getResponses().values().stream().map(ApiResponse::getContent) + .filter(Objects::nonNull) + .forEach(this::repairInlineOneOf); + } + } + } + } + } + } + + /** + * Add all OneOf schemas to #/components/schemas and replace them in the original content by ref schema + * Replace OneOf with unmodifiable types with an empty Schema + * + * OpenAPI Parser does not add inline OneOf schemas to models to generate + * + * @param content a 'content' section in the OAS specification. + */ + private void repairInlineOneOf(final Content content) { + content.values().forEach(mediaType -> { + final Schema replacingSchema = mediaType.getSchema(); + if (isOneOfSchema(replacingSchema)) { + if (ModelUtils.isSchemaOneOfConsistsOfCustomTypes(openAPI, replacingSchema)) { + final String oneOfModelName = (String) replacingSchema.getExtensions().get("x-one-of-name"); + final Schema newRefSchema = new Schema<>().$ref("#/components/schemas/" + oneOfModelName); + mediaType.setSchema(newRefSchema); + ModelUtils.getSchemas(openAPI).put(oneOfModelName, replacingSchema); + } else { + mediaType.setSchema(new Schema().type("object")); + } + } + }); + } + + private static boolean isOneOfSchema(final Schema schema) { + if (schema instanceof ComposedSchema) { + ComposedSchema composedSchema = (ComposedSchema) schema; + return Optional.ofNullable(composedSchema.getProperties()).map(Map::isEmpty).orElse(true) + && Optional.ofNullable(schema.getExtensions()).map(m -> m.containsKey("x-one-of-name")).orElse(false); + } + return false; + } + public void setUseSwaggerUI(boolean useSwaggerUI) { this.useSwaggerUI = useSwaggerUI; } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index 699c074633f5..62ff633a8113 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -1673,4 +1673,25 @@ public static SemVer getOpenApiVersion(OpenAPI openAPI, String location, List schema) { + if (schema instanceof ComposedSchema) { + ComposedSchema composedSchema = (ComposedSchema) schema; + if (composedSchema.getOneOf() == null || composedSchema.getOneOf().isEmpty()) { + return false; + } + for (Schema oneOfSchema : composedSchema.getOneOf()) { + if (oneOfSchema.get$ref() != null) { + oneOfSchema = ModelUtils.getReferencedSchema(openAPI, schema); + } + if (!(oneOfSchema instanceof ComposedSchema + || oneOfSchema instanceof MapSchema + || oneOfSchema instanceof ArraySchema + || oneOfSchema instanceof ObjectSchema)) { + return false; + } + } + } + return true; + } } diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache index 7ec79444bb9a..4c03a850a6f8 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache @@ -7,7 +7,7 @@ {{/discriminator}} {{>generatedAnnotation}} public interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { - {{#discriminator}} + {{^vendorExtensions.x-deduction}}{{#discriminator}} public {{propertyType}} {{propertyGetter}}(); - {{/discriminator}} + {{/discriminator}}{{/vendorExtensions.x-deduction}} } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache index 45990ffe202f..52868631dc95 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache @@ -109,9 +109,7 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}} {{/openApiNullable}} return this; } - {{/isArray}} - {{#isMap}} - +{{/isArray}}{{#isMap}}{{#items.datatypeWithEnum}} public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) { {{^required}} if (this.{{name}} == null) { @@ -121,7 +119,7 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}} this.{{name}}.put(key, {{name}}Item); return this; } - {{/isMap}} + {{/items.datatypeWithEnum}}{{/isMap}} {{! end feature: fluent setter methods }} {{! begin feature: getter and setter }} diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/typeInfoAnnotation.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/typeInfoAnnotation.mustache index c2b7f0c89dae..01ffb6bd16b4 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/typeInfoAnnotation.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/typeInfoAnnotation.mustache @@ -1,19 +1,25 @@ {{#jackson}} {{#discriminator.mappedModels}} {{#-first}} +{{#vendorExtensions.x-deduction}} +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, visible = true) +{{/vendorExtensions.x-deduction}} +{{^vendorExtensions.x-deduction}} @JsonIgnoreProperties( - value = "{{{discriminator.propertyBaseName}}}", // ignore manually set {{{discriminator.propertyBaseName}}}, it will be automatically generated by Jackson during serialization - allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization + value = "{{{discriminator.propertyBaseName}}}", // ignore manually set {{{discriminator.propertyBaseName}}}, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization ) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true) +{{/vendorExtensions.x-deduction}} @JsonSubTypes({ {{/-first}} - {{^vendorExtensions.x-discriminator-value}} - @JsonSubTypes.Type(value = {{modelName}}.class, name = "{{{mappingName}}}"){{^-last}},{{/-last}} - {{/vendorExtensions.x-discriminator-value}} - {{#vendorExtensions.x-discriminator-value}} - @JsonSubTypes.Type(value = {{modelName}}.class, name = "{{{vendorExtensions.x-discriminator-value}}}"){{^-last}},{{/-last}} - {{/vendorExtensions.x-discriminator-value}} +{{^vendorExtensions.x-discriminator-value}} + @JsonSubTypes.Type(value = {{modelName}}.class, name = "{{{mappingName}}}"){{^-last}},{{/-last}} +{{/vendorExtensions.x-discriminator-value}} +{{#vendorExtensions.x-discriminator-value}} + @JsonSubTypes.Type(value = {{modelName}}.class, name = "{{{vendorExtensions.x-discriminator-value}}}"){{^-last}},{{/-last}} +{{/vendorExtensions.x-discriminator-value}} {{#-last}} }) {{/-last}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index cd7a9c95b6a2..2b3191f96e5b 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -30,14 +30,27 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.parser.core.models.ParseOptions; +import org.openapitools.codegen.*; +import org.openapitools.codegen.languages.SpringCodegen; +import org.openapitools.codegen.languages.features.CXFServerFeatures; +import org.openapitools.codegen.utils.ModelUtils; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; @@ -56,13 +69,8 @@ import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.TestUtils; import org.openapitools.codegen.languages.AbstractJavaCodegen; -import org.openapitools.codegen.languages.SpringCodegen; -import org.openapitools.codegen.languages.features.CXFServerFeatures; import org.openapitools.codegen.languages.features.DocumentationProviderFeatures; -import org.testng.Assert; -import org.testng.annotations.DataProvider; import org.testng.annotations.Ignore; -import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; @@ -1322,4 +1330,140 @@ public void shouldSetDefaultValueForMultipleArrayItems() throws IOException { .assertParameterAnnotations() .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"\"")); } + + @Test(dataProvider = "specifications") + public void oneOfModelsGeneration(String specificationFile) throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/spring/" + specificationFile); + final CodegenConfig codegen = new SpringCodegen(); + codegen.setOpenAPI(openAPI); + codegen.setOutputDir(output.getAbsolutePath()); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + generator.opts(input).generate(); + + final String responseCode = "200"; + final String extension = "x-one-of-name"; + final Operation operation = openAPI.getPaths().get("/addFruits").getPost(); + List oneOfModels = new ArrayList<>(); + + // If response body contains oneOf definition - add OneOf model + final ApiResponse apiResponse = operation.getResponses().get(responseCode); + final Schema responseSchema = ModelUtils.getSchemaFromResponse(apiResponse); + if (ModelUtils.isArraySchema(responseSchema)) { + Schema responseItems = ((ArraySchema) responseSchema).getItems(); + if (responseItems.get$ref() == null) { + oneOfModels.add((String) (responseItems.getExtensions().get(extension))); + } + } + + // If request body contains oneOf definition - add OneOf model + final RequestBody requestBody = operation.getRequestBody(); + final Schema requestSchema = ModelUtils.getSchemaFromRequestBody(requestBody); + if (ModelUtils.isArraySchema(requestSchema)) { + Schema requestItems = ((ArraySchema) requestSchema).getItems(); + if (requestItems.get$ref() == null) { + oneOfModels.add((String) (requestItems.getExtensions().get(extension))); + } + } + + List models = new ArrayList<>(); + // If model contains discriminator - add to OneOf models, otherwise - generic models + openAPI.getComponents().getSchemas().forEach((modelName, modelSchema) -> { + if (modelSchema.getDiscriminator() != null || (modelSchema.getExtensions() != null && modelSchema.getExtensions().containsKey("x-one-of-name"))) { + oneOfModels.add(modelName); + } else { + // exclude allOf models + if (!modelName.contains("_")) { + models.add(modelName); + } + } + }); + Assert.assertFalse(oneOfModels.isEmpty()); + + final String pathFormat = "%s/%s/%s.java"; + final String relativePath = "/src/main/java/org/openapitools/model"; + final String jacksonSubTypeFormat = "@JsonSubTypes.Type(value = %s.class, name = \"%s\")"; + + models.forEach(modelName -> { + final String modelPath = String.format(Locale.ROOT, pathFormat, outputPath, relativePath, modelName); + + oneOfModels.forEach(oneOfModelName -> { + // Models should implement all linked OneOf interfaces + assertFileContains(Paths.get(modelPath), oneOfModelName); + + // OneOf model should contain relevant jackson annotations + final String oneOfPath = String.format(Locale.ROOT, pathFormat, outputPath, relativePath, oneOfModelName); + assertFileContains(Paths.get(oneOfPath), String.format(Locale.ROOT, jacksonSubTypeFormat, modelName, modelName)); + }); + }); + } + + @Test(dataProvider = "baseClassSpecifications") + public void oneOfShouldBeObject(String specificationFile) throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/spring/" + specificationFile); + final CodegenConfig codegen = new SpringCodegen(); + codegen.setOpenAPI(openAPI); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.setEnablePostProcessFile(true); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + generator.opts(input).generate(); + + final String pathFormat = "%s/%s/%s.java"; + final String relativePath = "/src/main/java/org/openapitools/api"; + + // OneOf model should be replaced with object + final String oneOfPath = String.format(Locale.ROOT, pathFormat, outputPath, relativePath, "AddFruitsApi"); + assertFileContains(Paths.get(oneOfPath), "ResponseEntity", "Object body"); + } + + @DataProvider(name = "specifications") + public static Object[][] specificationsProviderMethod() { + return new Object[][] { + { "oneOf_inherited_class.yaml" }, + { "oneOf_inherited_class_array.yaml" }, + { "oneOf_interface.yaml" }, + { "oneOf_interface_array.yaml" }, + { "oneOf_with_allOf_inherited_class.yaml" }, + { "oneOf_with_allOf_inherited_class_array.yaml" }, + }; + } + + @DataProvider(name = "baseClassSpecifications") + public static Object[][] baseClassSpecificationsProviderMethod() { + return new Object[][] { + { "oneOf_interface_base_classes.yaml" }, + { "oneOf_interface_base_classes_combined.yaml" } + }; + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_inherited_class.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_inherited_class.yaml new file mode 100644 index 000000000000..d2db0731b793 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_inherited_class.yaml @@ -0,0 +1,46 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "API should have import for OneOf Class, models should extend OneOf Class" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + $ref: '#/components/schemas/Fruit' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Fruit' +components: + schemas: + Fruit: + type: object + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' + discriminator: + propertyName: kind + Apple: + type: object + properties: + kind: + type: string + identifier: + type: string + required: + - kind + Orange: + type: object + properties: + kind: + type: string + identifier2: + type: string + required: + - kind \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_inherited_class_array.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_inherited_class_array.yaml new file mode 100644 index 000000000000..8e542d9d9eef --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_inherited_class_array.yaml @@ -0,0 +1,50 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "API should have import for OneOf Class, models should extend OneOf Class" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Fruit' + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Fruit' +components: + schemas: + Fruit: + type: object + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' + discriminator: + propertyName: kind + Apple: + type: object + properties: + kind: + type: string + identifier: + type: string + required: + - kind + Orange: + type: object + properties: + kind: + type: string + identifier2: + type: string + required: + - kind \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface.yaml new file mode 100644 index 000000000000..a35325825e59 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface.yaml @@ -0,0 +1,52 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "OneOf interface should be generated, API has link to OneOf, models implement OneOf interface" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' + discriminator: + propertyName: kind + requestBody: + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' +components: + schemas: + Apple: + type: object + properties: + kind: + type: string + identifier: + type: string + required: + - kind + Orange: + type: object + properties: + kind: + type: string + identifier2: + type: string + required: + - kind + Fruit: + type: object + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' + discriminator: + propertyName: kind \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_array.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_array.yaml new file mode 100644 index 000000000000..286c2e1a0226 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_array.yaml @@ -0,0 +1,51 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "OneOf interface should be generated, API has link to OneOf, models implement OneOf interface" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + type: array + items: + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' + discriminator: + propertyName: kind + requestBody: + content: + application/json: + schema: + type: array + items: + oneOf: + - $ref: '#/components/schemas/Apple' + - $ref: '#/components/schemas/Orange' + discriminator: + propertyName: kind +components: + schemas: + Apple: + type: object + properties: + kind: + type: string + identifier: + type: string + required: + - kind + Orange: + type: object + properties: + kind: + type: string + identifier2: + type: string + required: + - kind \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_base_classes.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_base_classes.yaml new file mode 100644 index 000000000000..71d62299351f --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_base_classes.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "OneOf interface should be generated, API has link to OneOf, models implement OneOf interface" +paths: + /addFruits: + post: + operationId: "addFruits" + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + x-one-of-name: "AddFruitsOneOf" + oneOf: + - type: string + format: date + - type: string + format: date-time + requestBody: + content: + application/json: + schema: + x-one-of-name: "AddFruitsOneOf" + oneOf: + - type: string + format: date + - type: string + format: date-time \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_base_classes_combined.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_base_classes_combined.yaml new file mode 100644 index 000000000000..5cab8ff61b06 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_interface_base_classes_combined.yaml @@ -0,0 +1,38 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "OneOf interface should be generated, API has link to OneOf, models implement OneOf interface" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + x-one-of-name: "AddFruitsOneOf" + oneOf: + - type: string + format: date + - $ref: '#/components/schemas/Apple' + requestBody: + content: + application/json: + schema: + x-one-of-name: "AddFruitsOneOf" + oneOf: + - type: string + format: date + - $ref: '#/components/schemas/Apple' +components: + schemas: + Apple: + type: object + properties: + kind: + type: string + identifier: + type: string + required: + - kind \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_with_allOf_inherited_class.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_with_allOf_inherited_class.yaml new file mode 100644 index 000000000000..37d8afc14490 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_with_allOf_inherited_class.yaml @@ -0,0 +1,46 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "API should have import for OneOf Class, models should extend OneOf Class" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + $ref: '#/components/schemas/Fruit' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Fruit' +components: + schemas: + Apple: + type: object + allOf: + - $ref: '#/components/schemas/Fruit' + - type: object + properties: + identifier: + type: string + Orange: + type: object + allOf: + - $ref: '#/components/schemas/Fruit' + - type: object + properties: + identifier2: + type: string + Fruit: + type: object + properties: + kind: + type: string + required: + - kind + discriminator: + propertyName: kind \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_with_allOf_inherited_class_array.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_with_allOf_inherited_class_array.yaml new file mode 100644 index 000000000000..17fa81801cf2 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/oneOf_with_allOf_inherited_class_array.yaml @@ -0,0 +1,50 @@ +openapi: 3.0.0 +info: + version: "1.0.0" + title: "API should have import for OneOf Class, models should extend OneOf Class" +paths: + /addFruits: + post: + responses: + '200': + description: Returns a list of fruits + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Fruit' + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Fruit' +components: + schemas: + Apple: + type: object + allOf: + - $ref: '#/components/schemas/Fruit' + - type: object + properties: + identifier: + type: string + Orange: + type: object + allOf: + - $ref: '#/components/schemas/Fruit' + - type: object + properties: + identifier2: + type: string + Fruit: + type: object + properties: + kind: + type: string + required: + - kind + discriminator: + propertyName: kind \ No newline at end of file