[BUG] StackOverflow Error Swift5 CodeGeneration
Created by: Donkov76
Bug Report Checklist
-
Have you provided a full/minimal spec to reproduce the issue? The following valid yaml creates StackOverflow Errors: -
Have you validated the input using an OpenAPI validator (example)? -
Have you tested with the latest master to confirm the issue still exists? -
Have you searched for related issues/PRs? -
What's the actual output vs expected output? Expected: no Stackoverflow -
[Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
Generating a Swift5 Client from the yaml file below produces StackOverflow Errors.
org.openapitools.codegen.CodegenModel.hashCode(CodegenModel.java:804) at java.base/java.util.Arrays.hashCode(Arrays.java:4498) at java.base/java.util.Objects.hash(Objects.java:133) at org.openapitools.codegen.CodegenModel.hashCode(CodegenModel.java:804) at java.base/java.util.ArrayList.hashCodeRange(ArrayList.java:595) at java.base/java.util.ArrayList.hashCode(ArrayList.java:582) at java.base/java.util.Arrays.hashCode(Arrays.java:4498) at java.base/java.util.Objects.hash(Objects.java:133) at org.openapitools.codegen.CodegenModel.hashCode(CodegenModel.java:804) at java.base/java.util.Arrays.hashCode(Arrays.java:4498) at java.base/java.util.Objects.hash(Objects.java:133) at org.openapitools.codegen.CodegenModel.hashCode(CodegenModel.java:804) at java.base/java.util.ArrayList.hashCodeRange(ArrayList.java:595) at java.base/java.util.ArrayList.hashCode(ArrayList.java:582) at java.base/java.util.Arrays.hashCode(Arrays.java:4498) at java.base/java.util.Objects.hash(Objects.java:133) at org.openapitools.codegen.CodegenModel.hashCode(CodegenModel.java:804)
After I fixed this the following Error occurred:
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1105)
at org.openapitools.codegen.languages.Swift5ClientCodegen.constructExampleCode(Swift5ClientCodegen.java:1091)
openapi-generator version
openapi-generator-cli 5.0.1 I also tested it with the current master branch
OpenAPI declaration file content or url
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
Generation Details
Steps to reproduce
openapi-generator generate -i "Swift5CodeGenarationBug2.yaml" -g swift5
Related issues/PRs
Suggest a fix
In my opinion there are 2 different bugs
- The hashCode implementation in org.openapitools.codegen.CodegenModel causes a overflow, because parent and children Models are both in the hash. My workaround for this issue was to add just the type and not the model to the visitedModel Set. (In Swift5ClientCodegen constructExampleCode)
I replaced all occurrences of
visitedModels.contains(modelMaps.get(codegenProperty.dataType))
with
visitedModels.contains(codegenProperty.dataType)
- constructExampleCode in org.openapitools.codegen.languagesSwift5ClientCodegen updates the visitedModel Map only in "constructExampleCode(CodegenParameter codegenParameter" and not in "constructExampleCode(CodegenProperty codegenProperty".
I suggest to add
visitedModels.add(codegenProperty.dataType);
in constructExampleCode(CodegenProperty codegenProperty,
public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
if (codegenProperty.isArray) { // array
return "[" + constructExampleCode(codegenProperty.items, modelMaps, visitedModels) + "]";
} else if (codegenProperty.isMap) { // TODO: map, file type
return "\"TODO\"";
} else if (languageSpecificPrimitives.contains(codegenProperty.dataType)) { // primitive type
if ("String".equals(codegenProperty.dataType) || "Character".equals(codegenProperty.dataType)) {
if (StringUtils.isEmpty(codegenProperty.example)) {
return "\"" + codegenProperty.example + "\"";
} else {
return "\"" + codegenProperty.name + "_example\"";
}
} else if ("Bool".equals(codegenProperty.dataType)) { // boolean
if (Boolean.parseBoolean(codegenProperty.example)) {
return "true";
} else {
return "false";
}
} else if ("URL".equals(codegenProperty.dataType)) { // URL
return "URL(string: \"https://example.com\")!";
} else if ("Date".equals(codegenProperty.dataType)) { // date
return "Date()";
} else { // numeric
if (StringUtils.isEmpty(codegenProperty.example)) {
return codegenProperty.example;
} else {
return "123";
}
}
} else {
// look up the model
if (modelMaps.containsKey(codegenProperty.dataType)) {
if (visitedModels.contains(codegenProperty.dataType)) {
// recursive/self-referencing model, simply return nil to avoid stackoverflow
return "nil";
} else {
visitedModels.add(codegenProperty.dataType); // <--- Add this Line
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, visitedModels);
}
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenProperty.dataType);
return "\"TODO\"";
}
}
}
The best solution may be to fix the hashCode Implementation in CodegenModel, but this could be a risky change. Maybe it is a good idea to add an option to disable the sample code generation.