diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonExperimentalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonExperimentalClientCodegen.java index 6f334fd78999..66ba6f428ad8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonExperimentalClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonExperimentalClientCodegen.java @@ -1679,23 +1679,6 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen { return null; } - /** - * Function to isolate the call to add schemas to the includedSchemas list that will detect when - * a schema is added multiple times. - * @param includedSchemas List of includedSchemas from toExampleValueRecursive - * @param schema the schema to add - */ - private void addSchemaToIncludedSchemaList(List includedSchemas, Schema schema) { - - // if the schema is in the list, then throw an exception. - // this should never happen - if(includedSchemas.contains(schema)) { - throw new RuntimeException("Attempted to add a schema to the includedSchemas list twice"); - } - - includedSchemas.add(schema); - } - /*** * Recursively generates string examples for schemas * @@ -1776,7 +1759,10 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen { Boolean hasProperties = (schema.getProperties() != null && !schema.getProperties().isEmpty()); CodegenDiscriminator disc = createDiscriminator(modelName, schema, openAPI); if (ModelUtils.isComposedSchema(schema)) { - addSchemaToIncludedSchemaList(includedSchemas, schema); + if(includedSchemas.contains(schema)) { + return ""; + } + includedSchemas.add(schema); // complex composed object type schemas not yet handled and the code returns early if (hasProperties) { // what if this composed schema defined properties + allOf? @@ -1941,7 +1927,10 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen { ArraySchema arrayschema = (ArraySchema) schema; Schema itemSchema = arrayschema.getItems(); String itemModelName = getModelName(itemSchema); - addSchemaToIncludedSchemaList(includedSchemas, schema); + if(includedSchemas.contains(schema)) { + return ""; + } + includedSchemas.add(schema); String itemExample = toExampleValueRecursive(itemModelName, itemSchema, objExample, indentationLevel + 1, "", exampleLine + 1, includedSchemas); if (StringUtils.isEmpty(itemExample) || cycleFound) { return fullPrefix + "[]" + closeChars; @@ -2018,7 +2007,11 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen { addPropPrefix = ensureQuotes(key) + ": "; } String addPropsModelName = getModelName(addPropsSchema); - addSchemaToIncludedSchemaList(includedSchemas, schema); + if(includedSchemas.contains(schema)) { + return ""; + } + includedSchemas.add(schema); + example = fullPrefix + "\n" + toExampleValueRecursive(addPropsModelName, addPropsSchema, addPropsExample, indentationLevel + 1, addPropPrefix, exampleLine + 1, includedSchemas) + ",\n" + closingIndentation + closeChars; } else { example = fullPrefix + closeChars; @@ -2035,14 +2028,18 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen { } private String exampleForObjectModel(Schema schema, String fullPrefix, String closeChars, CodegenProperty discProp, int indentationLevel, int exampleLine, String closingIndentation, List includedSchemas) { + Map requiredAndOptionalProps = schema.getProperties(); if (requiredAndOptionalProps == null || requiredAndOptionalProps.isEmpty()) { return fullPrefix + closeChars; } - String example = fullPrefix + "\n"; + if(includedSchemas.contains(schema)) { + return ""; + } + includedSchemas.add(schema); - addSchemaToIncludedSchemaList(includedSchemas, schema); + String example = fullPrefix + "\n"; for (Map.Entry entry : requiredAndOptionalProps.entrySet()) { String propName = entry.getKey(); @@ -2055,14 +2052,25 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen { propExample = discProp.example; } else { propModelName = getModelName(propSchema); - propExample = exampleFromStringOrArraySchema(propSchema, null, propName); + propExample = exampleFromStringOrArraySchema( + propSchema, + null, + propName); } - example += toExampleValueRecursive(propModelName, propSchema, propExample, indentationLevel + 1, propName + "=", exampleLine + 1, includedSchemas) + ",\n"; + example += toExampleValueRecursive(propModelName, + propSchema, + propExample, + indentationLevel + 1, + propName + "=", + exampleLine + 1, + includedSchemas) + ",\n"; } + // TODO handle additionalProperties also example += closingIndentation + closeChars; return example; + } private Object exampleFromStringOrArraySchema(Schema sc, Object currentExample, String propName) { diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonExperimentalClientTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonExperimentalClientTest.java index 9337f4fe652d..284d3c415f7d 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonExperimentalClientTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonExperimentalClientTest.java @@ -20,6 +20,7 @@ import com.google.common.io.Resources; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.*; +import java.io.PrintWriter; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.PythonExperimentalClientCodegen; import org.openapitools.codegen.utils.ModelUtils; @@ -28,6 +29,7 @@ import org.testng.annotations.Test; import java.io.IOException; import java.nio.charset.StandardCharsets; +import org.testng.reporters.jq.Model; @SuppressWarnings("static-method") public class PythonExperimentalClientTest { @@ -74,24 +76,42 @@ public class PythonExperimentalClientTest { Assert.assertFalse(openAPI.getExtensions().containsValue("x-original-swagger-version")); } - @Test(description = "tests GeoJson Examples") - public void testRecursiveGeoJsonExample() throws IOException { - final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_13043_recursive_model.yaml"); + @Test(description = "tests GeoJson Example for GeoJsonGeometry") + public void testRecursiveGeoJsonExampleWhenTypeIsGeoJsonGeometry() throws IOException { + + testEndpointExampleValue("/geojson", + "src/test/resources/3_0/issue_13043_recursive_model.yaml", + "3_0/issue_13043_recursive_model_expected_value.txt"); + + + } + + @Test(description = "tests GeoJson Example for GeometryCollection") + public void testRecursiveGeoJsonExampleWhenTypeIsGeometryCollection() throws IOException { + + testEndpointExampleValue("/geojson_geometry_collection", + "src/test/resources/3_0/issue_13043_recursive_model.yaml", + "3_0/issue_13043_geometry_collection_expected_value.txt"); + + } + + private void testEndpointExampleValue(String endpoint, String specFilePath, String expectedAnswerPath) throws IOException { + final OpenAPI openAPI = TestUtils.parseFlattenSpec(specFilePath); final PythonExperimentalClientCodegen codegen = new PythonExperimentalClientCodegen(); codegen.setOpenAPI(openAPI); - final Operation operation = openAPI.getPaths().get("/geojson").getPost(); + final Operation operation = openAPI.getPaths().get(endpoint).getPost(); Schema schema = ModelUtils.getSchemaFromRequestBody(operation.getRequestBody()); String exampleValue = codegen.toExampleValue(schema, null); - // uncomment if you need to regenerate the expected value - // PrintWriter printWriter = new PrintWriter("src/test/resources/3_0/issue_8052_recursive_model_expected_value.txt"); - // printWriter.write(exampleValue); - // printWriter.close(); - // org.junit.Assert.assertTrue(false); + // uncomment if you need to regenerate the expected value + // PrintWriter printWriter = new PrintWriter("src/test/resources/" + expectedAnswerPath); + // printWriter.write(exampleValue); + // printWriter.close(); + // org.junit.Assert.assertTrue(false); String expectedValue = Resources.toString( - Resources.getResource("3_0/issue_13043_recursive_model_expected_value.txt"), + Resources.getResource(expectedAnswerPath), StandardCharsets.UTF_8); expectedValue = expectedValue.replaceAll("\\r\\n", "\n"); Assert.assertEquals(exampleValue.trim(), expectedValue.trim()); diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_13043_geometry_collection_expected_value.txt b/modules/openapi-generator/src/test/resources/3_0/issue_13043_geometry_collection_expected_value.txt new file mode 100644 index 000000000000..7d4d61650ba1 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/issue_13043_geometry_collection_expected_value.txt @@ -0,0 +1,4 @@ +GeometryCollection( + type="GeometryCollection", + geometries=[], + ) \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_13043_recursive_model.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_13043_recursive_model.yaml index 6d833b292110..9b9f5d34c3e0 100644 --- a/modules/openapi-generator/src/test/resources/3_0/issue_13043_recursive_model.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/issue_13043_recursive_model.yaml @@ -26,6 +26,26 @@ paths: schema: $ref: '#/components/schemas/GeoJsonGeometry' parameters: [] + /geojson_geometry_collection: + post: + summary: Add a GeoJson GeometryCollection Object + operationId: post-geojson-geometry-collection + responses: + '201': + description: Created + content: + application/json: + schema: + type: string + description: GeoJson ID + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GeometryCollection' + parameters: [] components: schemas: GeoJsonGeometry: