Fix for StackOverflow in Swift5 CodeGeneration Issue #8671 (#8672)

* StackOverflowFix for Issue 8671

* update samples

Co-authored-by: William Cheng <wing328hk@gmail.com>
This commit is contained in:
Markus Wandersee 2021-03-15 10:59:09 +01:00 committed by GitHub
parent bf859c640e
commit fae4d7a73d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 152 additions and 17 deletions

View File

@ -999,13 +999,13 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation"); List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation operation : operations) { for (CodegenOperation operation : operations) {
for (CodegenParameter cp : operation.allParams) { for (CodegenParameter cp : operation.allParams) {
cp.vendorExtensions.put("x-swift-example", constructExampleCode(cp, modelMaps, new HashSet())); cp.vendorExtensions.put("x-swift-example", constructExampleCode(cp, modelMaps, new HashSet<String>()));
} }
} }
return objs; return objs;
} }
public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps, Set visitedModels) { public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
if (codegenParameter.isArray) { // array if (codegenParameter.isArray) { // array
return "[" + constructExampleCode(codegenParameter.items, modelMaps, visitedModels) + "]"; return "[" + constructExampleCode(codegenParameter.items, modelMaps, visitedModels) + "]";
} else if (codegenParameter.isMap) { // TODO: map, file type } else if (codegenParameter.isMap) { // TODO: map, file type
@ -1037,11 +1037,11 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
} else { // model } else { // model
// look up the model // look up the model
if (modelMaps.containsKey(codegenParameter.dataType)) { if (modelMaps.containsKey(codegenParameter.dataType)) {
if (visitedModels.contains(modelMaps.get(codegenParameter.dataType))) { if (visitedModels.contains(codegenParameter.dataType)) {
// recursive/self-referencing model, simply return nil to avoid stackoverflow // recursive/self-referencing model, simply return nil to avoid stackoverflow
return "nil"; return "nil";
} else { } else {
visitedModels.add(modelMaps.get(codegenParameter.dataType)); visitedModels.add(codegenParameter.dataType);
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps, visitedModels); return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps, visitedModels);
} }
} else { } else {
@ -1051,7 +1051,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
} }
} }
public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, Set visitedModels) { public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
if (codegenProperty.isArray) { // array if (codegenProperty.isArray) { // array
return "[" + constructExampleCode(codegenProperty.items, modelMaps, visitedModels) + "]"; return "[" + constructExampleCode(codegenProperty.items, modelMaps, visitedModels) + "]";
} else if (codegenProperty.isMap) { // TODO: map, file type } else if (codegenProperty.isMap) { // TODO: map, file type
@ -1083,10 +1083,11 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
} else { } else {
// look up the model // look up the model
if (modelMaps.containsKey(codegenProperty.dataType)) { if (modelMaps.containsKey(codegenProperty.dataType)) {
if (visitedModels.contains(modelMaps.get(codegenProperty.dataType))) { if (visitedModels.contains(codegenProperty.dataType)) {
// recursive/self-referencing model, simply return nil to avoid stackoverflow // recursive/self-referencing model, simply return nil to avoid stackoverflow
return "nil"; return "nil";
} else { } else {
visitedModels.add(codegenProperty.dataType);
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, visitedModels); return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, visitedModels);
} }
} else { } else {
@ -1096,7 +1097,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
} }
} }
public String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps, Set visitedModels) { public String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
String example; String example;
example = codegenModel.name + "("; example = codegenModel.name + "(";
List<String> propertyExamples = new ArrayList<>(); List<String> propertyExamples = new ArrayList<>();

View File

@ -185,4 +185,37 @@ public class Swift5ClientCodegenTest {
} }
} }
@Test(description = "Bug example code generation 2", enabled = true)
public void crashSwift5ExampleCodeGenerationStackOverflowBug_2Test() throws IOException {
//final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/bugs/Swift5CodeGenerationStackOverflow#2966.yaml");
Path target = Files.createTempDirectory("test");
File output = target.toFile();
try {
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("swift5")
.setValidateSpec(false)
// .setInputSpec("http://localhost:8080/api/openapi.yaml")
.setInputSpec("src/test/resources/bugs/Swift5CodeGenarationBug2.yaml")
//.setInputSpec("http://localhost:8080/api/openapi.yaml")
.setEnablePostProcessFile(true)
.setOutputDir(target.toAbsolutePath().toString());
final ClientOptInput clientOptInput = configurator.toClientOptInput();
DefaultGenerator generator = new DefaultGenerator(false);
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.ENABLE_POST_PROCESS_FILE, "true");
List<File> files = generator.opts(clientOptInput).generate();
Assert.assertTrue(files.size() > 0, "No files generated");
} finally {
output.delete();
}
}
} }

View File

@ -0,0 +1,101 @@
openapi: 3.0.1
info:
title: XXX
description: Das ist jetzt der erste OpenAPI 3.0 Endpoint
contact:
email: XXX.XXX@XXX.de
version: "1.0"
paths:
/api/v1/petresource/pet:
post:
tags:
- v1/petresource
summary: Save a Pet.
description: Save a Pet.
operationId: savePet
requestBody:
content:
'*/*':
schema:
$ref: '#/components/schemas/Pet'
responses:
default:
description: PetResponse
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
/api/v1/petresource/petstore:
post:
tags:
- v1/petresource
summary: Save a Petstore.
description: Save a Petstore.
operationId: savePetStore
requestBody:
content:
'*/*':
schema:
$ref: '#/components/schemas/PetStore'
responses:
default:
description: PetStore
content:
application/json:
schema:
$ref: '#/components/schemas/PetStore'
components:
schemas:
Cat:
required:
- type
type: object
description: Cat
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
catFood:
type: string
Dog:
required:
- type
type: object
description: Dog
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
dogFood:
type: string
Pet:
required:
- type
type: object
properties:
name:
type: string
description: Name
store:
$ref: '#/components/schemas/PetStore'
mother:
$ref: '#/components/schemas/Pet'
father:
$ref: '#/components/schemas/Pet'
type:
type: string
description: Type Diskriminator
description: Base Pet
discriminator:
propertyName: type
mapping:
Dog: '#/components/schemas/Dog'
Cat: '#/components/schemas/Cat'
PetStore:
type: object
properties:
pets:
type: array
items:
$ref: '#/components/schemas/Pet'
description: PetStore

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -216,7 +216,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body).then { FakeAPI.testBodyWithFileSchema(body: body).then {
// when the promise is fulfilled // when the promise is fulfilled

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {

View File

@ -192,7 +192,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
// TODO RxSwift sample code not yet implemented. To contribute, please open a ticket via http://github.com/OpenAPITools/openapi-generator/issues/new // TODO RxSwift sample code not yet implemented. To contribute, please open a ticket via http://github.com/OpenAPITools/openapi-generator/issues/new
``` ```

View File

@ -228,7 +228,7 @@ For this test, the body for this request much reference a schema named `File`.
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new // The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import PetstoreClient import PetstoreClient
let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [File(sourceURI: "sourceURI_example")]) // FileSchemaTestClass | let body = FileSchemaTestClass(file: File(sourceURI: "sourceURI_example"), files: [nil]) // FileSchemaTestClass |
FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in FakeAPI.testBodyWithFileSchema(body: body) { (response, error) in
guard error == nil else { guard error == nil else {