diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/examples/ExampleGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/examples/ExampleGenerator.java index 8b6d0a630eac..010a0f93aaef 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/examples/ExampleGenerator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/examples/ExampleGenerator.java @@ -406,14 +406,27 @@ private void traverseSchemaProperties(String mediaType, Schema schema, Set processedModels, Map values) { List interfaces = schema.getAllOf(); + if (interfaces == null) { + return; + } + for (Schema composed : interfaces) { - traverseSchemaProperties(mediaType, composed, processedModels, values); if (composed.get$ref() != null) { String ref = ModelUtils.getSimpleRef(composed.get$ref()); + + if (processedModels.contains(ref)) { + LOGGER.warn("Circular reference detected in allOf for $ref: {}. Skipping.", ref); + continue; + } + Schema resolved = ModelUtils.getSchema(openAPI, ref); if (resolved != null) { + processedModels.add(ref); traverseSchemaProperties(mediaType, resolved, processedModels, values); + processedModels.remove(ref); } + } else { + traverseSchemaProperties(mediaType, composed, processedModels, values); } } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/ExampleGeneratorTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/ExampleGeneratorTest.java index 41a61a4c32fc..00cdbbec9a17 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/ExampleGeneratorTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/ExampleGeneratorTest.java @@ -8,7 +8,6 @@ import java.util.*; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import static org.testng.AssertJUnit.assertEquals; @@ -249,6 +248,68 @@ public void generateFromResponseSchemaWithAllOfComposedModel() throws Exception{ assertEquals("200", examples.get(0).get("statusCode")); } + @Test + public void generateFromResponseSchemaWithAllOfCircularSchema() throws Exception{ + OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml"); + + new InlineModelResolver().flatten(openAPI); + + ExampleGenerator exampleGenerator = new ExampleGenerator(openAPI.getComponents().getSchemas(), openAPI); + Set mediaTypeKeys = new TreeSet<>(); + mediaTypeKeys.add("application/json"); + List> examples = exampleGenerator.generateFromResponseSchema( + "200", + openAPI + .getPaths() + .get("/generate_from_response_schema_with_allOf_circular_model") + .getGet() + .getResponses() + .get("200") + .getContent() + .get("application/json") + .getSchema(), + mediaTypeKeys + ); + + ObjectMapper mapper = new ObjectMapper(); + + assertEquals(1, examples.size()); + assertEquals("application/json", examples.get(0).get("contentType")); + assertEquals(mapper.readTree(String.format(Locale.ROOT, "{%n \"example_schema_property_alloff_circular\" : \"example schema property allOff circular\"%n}")), mapper.readTree(examples.get(0).get("example"))); + assertEquals("200", examples.get(0).get("statusCode")); + } + + @Test + public void generateFromResponseSchemaWithAllOfSiblingSchema() throws Exception{ + OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml"); + + new InlineModelResolver().flatten(openAPI); + + ExampleGenerator exampleGenerator = new ExampleGenerator(openAPI.getComponents().getSchemas(), openAPI); + Set mediaTypeKeys = new TreeSet<>(); + mediaTypeKeys.add("application/json"); + List> examples = exampleGenerator.generateFromResponseSchema( + "200", + openAPI + .getPaths() + .get("/generate_from_response_schema_with_allOf_sibling_model") + .getGet() + .getResponses() + .get("200") + .getContent() + .get("application/json") + .getSchema(), + mediaTypeKeys + ); + + ObjectMapper mapper = new ObjectMapper(); + + assertEquals(1, examples.size()); + assertEquals("application/json", examples.get(0).get("contentType")); + assertEquals(mapper.readTree(String.format(Locale.ROOT, "{%n \"base\":{\"example_schema_property\":\"example schema property value\",\"example_schema_property_composed\":\"example schema property value composed\"}, \"sibling\":{\"example_schema_property\":\"example schema property value\",\"example_schema_property_composed\":\"example schema property value composed\"} %n}")), mapper.readTree(examples.get(0).get("example"))); + assertEquals("200", examples.get(0).get("statusCode")); + } + @Test public void generateFromResponseSchemaWithAllOfChildComposedModel() throws Exception { OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/example_generator_test.yaml"); diff --git a/modules/openapi-generator/src/test/resources/3_0/example_generator_test.yaml b/modules/openapi-generator/src/test/resources/3_0/example_generator_test.yaml index 020edb73b406..441e4e80caaa 100644 --- a/modules/openapi-generator/src/test/resources/3_0/example_generator_test.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/example_generator_test.yaml @@ -101,6 +101,26 @@ paths: application/json: schema: $ref: '#/components/schemas/ExampleAllOfParentSchema' + /generate_from_response_schema_with_allOf_circular_model: + get: + operationId: generateFromResponseSchemaWithAllOfCircularModel + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ExampleAllOfCircularSchema' + /generate_from_response_schema_with_allOf_sibling_model: + get: + operationId: generateFromResponseSchemaWithAllOfSiblingModel + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ExampleAllOfSiblingContainerSchema' /generate_from_response_schema_with_anyOf_composed_model: get: operationId: generateFromResponseSchemaWithAnyOfModel @@ -151,6 +171,15 @@ components: example_schema_property_composed: type: string example: example schema property value composed + ExampleAllOfSiblingSchema: + type: object + allOf: + - $ref: '#/components/schemas/ExampleSchema' + - type: object + properties: + example_schema_property_composed: + type: string + example: example schema property value composed ExampleAllOfParentSchema: type: object allOf: @@ -160,6 +189,22 @@ components: example_schema_property_composed_parent: type: string example: example schema property value composed parent + ExampleAllOfCircularSchema: + type: object + allOf: + - $ref: '#/components/schemas/ExampleAllOfCircularSchema' + - type: object + properties: + example_schema_property_alloff_circular: + type: string + example: example schema property allOff circular + ExampleAllOfSiblingContainerSchema: + type: object + properties: + base: + $ref: '#/components/schemas/ExampleAllOfSchema' + sibling: + $ref: '#/components/schemas/ExampleAllOfSiblingSchema' ExampleAnyOfSchema: type: object anyOf: