From 0d62a628a7a372cd8e3bcfc68caca47e4c58763b Mon Sep 17 00:00:00 2001 From: bear43 Date: Mon, 24 Apr 2023 17:37:41 +0300 Subject: [PATCH 1/2] Fix issue #15298 --- .../openapitools/codegen/DefaultCodegen.java | 15 ++-- .../java/spring/SpringCodegenTest.java | 33 +++++++++ .../issue_spring_codegen_polymorphism.yaml | 74 +++++++++++++++++++ 3 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/3_0/issue_spring_codegen_polymorphism.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 2c1414d21ce3..11896c48f679 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -3147,8 +3147,12 @@ protected void setAddProps(Schema schema, IJsonSchemaValidationProperties proper * @param sc The Schema that may contain the discriminator * @param discPropName The String that is the discriminator propertyName in the schema */ - private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, String discPropName, OpenAPI openAPI) { + private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, String discPropName, OpenAPI openAPI, Set visitedSchemas) { Schema refSchema = ModelUtils.getReferencedSchema(openAPI, sc); + if (visitedSchemas.contains(refSchema)) { + return null; + } + visitedSchemas.add(refSchema); if (refSchema.getProperties() != null && refSchema.getProperties().get(discPropName) != null) { Schema discSchema = (Schema) refSchema.getProperties().get(discPropName); CodegenProperty cp = new CodegenProperty(); @@ -3166,7 +3170,7 @@ private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, if (composedSchema.getAllOf() != null) { // If our discriminator is in one of the allOf schemas break when we find it for (Schema allOf : composedSchema.getAllOf()) { - CodegenProperty cp = discriminatorFound(composedSchemaName, allOf, discPropName, openAPI); + CodegenProperty cp = discriminatorFound(composedSchemaName, allOf, discPropName, openAPI, visitedSchemas); if (cp != null) { return cp; } @@ -3177,7 +3181,7 @@ private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, CodegenProperty cp = new CodegenProperty(); for (Schema oneOf : composedSchema.getOneOf()) { String modelName = ModelUtils.getSimpleRef(oneOf.get$ref()); - CodegenProperty thisCp = discriminatorFound(composedSchemaName, oneOf, discPropName, openAPI); + CodegenProperty thisCp = discriminatorFound(composedSchemaName, oneOf, discPropName, openAPI, visitedSchemas); if (thisCp == null) { LOGGER.warn( "'{}' defines discriminator '{}', but the referenced OneOf schema '{}' is missing {}", @@ -3200,7 +3204,7 @@ private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, CodegenProperty cp = new CodegenProperty(); for (Schema anyOf : composedSchema.getAnyOf()) { String modelName = ModelUtils.getSimpleRef(anyOf.get$ref()); - CodegenProperty thisCp = discriminatorFound(composedSchemaName, anyOf, discPropName, openAPI); + CodegenProperty thisCp = discriminatorFound(composedSchemaName, anyOf, discPropName, openAPI, visitedSchemas); if (thisCp == null) { LOGGER.warn( "'{}' defines discriminator '{}', but the referenced AnyOf schema '{}' is missing {}", @@ -3355,7 +3359,8 @@ protected List getOneOfAnyOfDescendants(String composedSchemaName, "Invalid inline schema defined in oneOf/anyOf in '{}'. Per the OpenApi spec, for this case when a composed schema defines a discriminator, the oneOf/anyOf schemas must use $ref. Change this inline definition to a $ref definition", composedSchemaName); } - CodegenProperty df = discriminatorFound(composedSchemaName, sc, discPropName, openAPI); + HashSet visitedSchemas = new HashSet<>(); + CodegenProperty df = discriminatorFound(composedSchemaName, sc, discPropName, openAPI, visitedSchemas); String modelName = ModelUtils.getSimpleRef(ref); if (df == null || !df.isString || df.required != true) { String msgSuffix = ""; 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 0b2f04642453..5b4b2c1c1f13 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 @@ -2670,4 +2670,37 @@ public void testEnumCaseSensitive_issue8084() throws IOException { .bodyContainsLines("if (b.value.equals(value)) {"); } + @Test + public void shouldNotFallWithNPEOrStackOverflow() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/3_0/issue_spring_codegen_polymorphism.yaml", null, new ParseOptions()).getOpenAPI(); + + SpringCodegen codegen = new SpringCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(SpringCodegen.DATE_LIBRARY, "java8-localdatetime"); + codegen.additionalProperties().put(INTERFACE_ONLY, "true"); + codegen.additionalProperties().put(USE_ONE_OF_INTERFACES, "false"); + codegen.additionalProperties().put(CodegenConstants.SERIALIZABLE_MODEL, "true"); + codegen.additionalProperties().put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true"); + codegen.additionalProperties().put(USE_TAGS, "true"); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + generator.setGeneratorPropertyDefault(CodegenConstants.LIBRARY, "spring-cloud"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + List generate = generator.opts(input).generate(); + System.out.println(generate); + } + } diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_spring_codegen_polymorphism.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_spring_codegen_polymorphism.yaml new file mode 100644 index 000000000000..131e5adbd0d0 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/issue_spring_codegen_polymorphism.yaml @@ -0,0 +1,74 @@ +openapi: 3.0.2 +info: + title: Polymorphism Java Example + version: 1.0.0 + contact: + name: polydectes + email: 12345@sharklasers.com +servers: + - url: 'https://localhost' +tags: + - name: Example +paths: + '/animal': + post: + tags: + - Example + operationId: createAnAnimal + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Animal' + responses: + '200': + $ref: '#/components/responses/200-OK' + '400': + $ref: '#/components/responses/400-BadRequest' +components: + responses: + 200-OK: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Animal' + 400-BadRequest: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + schemas: + Animal: + type: object + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + discriminator: + propertyName: animalType + Cat: + type: object + allOf: + - $ref: '#/components/schemas/Animal' + properties: + acceptableAsHousepet: + type: boolean + Dog: + type: object + allOf: + - $ref: '#/components/schemas/Animal' + properties: + canBeTrained: + type: string + OkResponse: + type: object + properties: + id: + type: string + ErrorResponse: + type: object + properties: + message: + type: string \ No newline at end of file From 4e802f7097ccc635fb43b8c2e5e54c258197068d Mon Sep 17 00:00:00 2001 From: bear43 Date: Mon, 24 Apr 2023 18:06:23 +0300 Subject: [PATCH 2/2] Fix #15298 --- .../openapitools/codegen/java/spring/SpringCodegenTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 5b4b2c1c1f13..6ab17fca2f2d 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 @@ -2699,8 +2699,7 @@ public void shouldNotFallWithNPEOrStackOverflow() throws IOException { generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); - List generate = generator.opts(input).generate(); - System.out.println(generate); + generator.opts(input).generate(); } }