diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java index 9738d9207281..4793dae5f9f9 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java @@ -442,7 +442,19 @@ private void processNestedSchemas(Schema schema, Set visitedSchemas) { List oneOfs = schema.getOneOf(); List newOneOfs = new ArrayList<>(); for (Schema oneOf : oneOfs) { - Schema oneOfSchema = ModelUtils.getReferencedSchema(openAPI, oneOf); + Schema oneOfSchema = oneOf; + if (ModelUtils.isAllOf(oneOf) && oneOf.getAllOf() != null && oneOf.getAllOf().size() == 1) { + Object allOfObj = oneOf.getAllOf().get(0); + if (allOfObj instanceof Schema) { + Schema allOfItem = (Schema) allOfObj; + if (StringUtils.isNotEmpty(allOfItem.get$ref())) { + oneOfSchema = ModelUtils.getReferencedSchema(openAPI, allOfItem); + } + } + } else { + oneOfSchema = ModelUtils.getReferencedSchema(openAPI, oneOf); + } + if (ModelUtils.isArraySchema(oneOfSchema)) { Schema innerSchema = generateNestedSchema(oneOfSchema, visitedSchemas); innerSchema.setTitle(oneOf.getTitle()); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/protobuf/ProtobufSchemaCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/protobuf/ProtobufSchemaCodegenTest.java index b22a45b50395..40d0f3f81b80 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/protobuf/ProtobufSchemaCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/protobuf/ProtobufSchemaCodegenTest.java @@ -18,8 +18,10 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.BooleanSchema; import io.swagger.v3.oas.models.media.IntegerSchema; import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.NumberSchema; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; @@ -45,6 +47,7 @@ import java.util.List; import java.util.Map; + import static org.openapitools.codegen.TestUtils.createCodegenModelWrapper; import static org.openapitools.codegen.languages.ProtobufSchemaCodegen.USE_SIMPLIFIED_ENUM_NAMES; import static org.testng.Assert.assertEquals; @@ -142,6 +145,64 @@ public void testCodeGenWithPrimitiveAnyOf() throws IOException { output.deleteOnExit(); } + @Test + public void testCodeGenWithOneOfDiscriminator31() throws IOException { + System.setProperty("line.separator", "\n"); + + File output = Files.createTempDirectory("test").toFile(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("protobuf-schema") + .setInputSpec("src/test/resources/3_1/oneOf.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(clientOptInput).generate(); + + TestUtils.ensureContainsFile(files, output, "models/fruit.proto"); + + // Get the processed OpenAPI with wrapper schemas + OpenAPI openAPI = clientOptInput.getOpenAPI(); + ProtobufSchemaCodegen codegen = new ProtobufSchemaCodegen(); + codegen.setOpenAPI(openAPI); + codegen.processOpts(); + + Schema fruitSchema = openAPI.getComponents().getSchemas().get("fruit"); + Assert.assertNotNull(fruitSchema, "fruit schema should exist"); + + CodegenModel fruitModel = codegen.fromModel("fruit", fruitSchema); + codegen.postProcessModels(createCodegenModelWrapper(fruitModel)); + + Assert.assertNotNull(fruitModel.oneOf, "fruit model should have oneOf items"); + Assert.assertTrue(fruitModel.oneOf.size() >= 2, "fruit model should have at least 2 oneOf items"); + + Assert.assertNotNull(fruitModel.vars, "fruit model should have vars"); + Assert.assertTrue(fruitModel.vars.size() > 0, "fruit model should have at least one var"); + + Assert.assertEquals(fruitModel.vars.size(), 3, "fruit model should have 3 vars (one for each oneOf item)"); + + for (CodegenProperty var : fruitModel.vars) { + Assert.assertNotNull(var.name, "var name should not be null"); + Assert.assertNotNull(var.dataType, "var dataType should not be null"); + Assert.assertTrue(var.isModel, "var " + var.name + " should be a model type (isModel=" + var.isModel + ")"); + Assert.assertFalse(var.isContainer, "var should not be a container (it references a model)"); + + // Check expected properties based on discriminator title + if (var.name.equals("apple_list")) { + Assert.assertEquals(var.dataType, "StringArray", "apple_list should reference StringArray"); + } else if (var.name.equals("banana_map")) { + Assert.assertEquals(var.dataType, "FloatMap", "banana_map should reference FloatMap"); + } else if (var.name.equals("orange_choice")) { + Assert.assertEquals(var.dataType, "Orange", "orange_choice should reference Orange"); + } else { + Assert.fail("Unexpected var name: " + var.name + ". Expected one of: apple_list, banana_map, orange_choice"); + } + } + + output.deleteOnExit(); + } + @Test(description = "convert a model with dollar signs") public void modelTest() { final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/dollar-in-names-pull14359.yaml"); diff --git a/modules/openapi-generator/src/test/resources/3_1/oneOf.yaml b/modules/openapi-generator/src/test/resources/3_1/oneOf.yaml new file mode 100644 index 000000000000..fe3549d551a8 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_1/oneOf.yaml @@ -0,0 +1,42 @@ +openapi: 3.1.0 + +info: + title: fruity + version: 0.0.1 + +paths: + /: + get: + responses: + '200': + description: desc + content: + application/json: + schema: + $ref: '#/components/schemas/fruit' + +components: + schemas: + fruit: + oneOf: + - title: appleList + $ref: '#/components/schemas/appleArray' + - title: bananaMap + $ref: '#/components/schemas/bananaMap' + - title: orangeChoice + $ref: '#/components/schemas/orange' + appleArray: + type: array + items: + title: appleaArray + type: string + bananaMap: + type: object + additionalProperties: + type: number + orange: + title: orange + type: object + properties: + sweet: + type: boolean