diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java index dba1721fbca2..6d00e02103e2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java @@ -756,5 +756,10 @@ public LinkedHashMap getContent() { public void setContent(LinkedHashMap content) { this.content = content; } + + @Override + public String getBaseType() { + return baseType; + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java index 7a23b3ab7267..33fcf0afa520 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java @@ -614,4 +614,9 @@ public CodegenComposedSchemas getComposedSchemas() { @Override public void setHasMultipleTypes(boolean hasMultipleTypes) { this.hasMultipleTypes = hasMultipleTypes; } + + @Override + public String getBaseType() { + return baseType; + } } 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 95df82d2ddf6..307507729514 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 @@ -5120,12 +5120,32 @@ private static String generateNextName(String name) { } } + protected void addImports(CodegenModel m, IJsonSchemaValidationProperties type) { + addImports(m.imports, type); + } + + protected void addImports(Set importsToBeAddedTo, IJsonSchemaValidationProperties type) { + addImports(importsToBeAddedTo, type.getImports(true)); + } + + protected void addImports(Set importsToBeAddedTo, Set importsToAdd) { + importsToAdd.stream().forEach(i -> addImport(importsToBeAddedTo, i)); + } + protected void addImport(CodegenModel m, String type) { - if (type != null && needToImport(type)) { - m.imports.add(type); + addImport(m.imports, type); + } + + private void addImport(Set importsToBeAddedTo, String type) { + if (shouldAddImport(type)) { + importsToBeAddedTo.add(type); } } + private boolean shouldAddImport(String type) { + return type != null && needToImport(type); + } + /** * Loop through properties and unalias the reference if $ref (reference) is defined * @@ -5262,17 +5282,10 @@ protected void addVars(IJsonSchemaValidationProperties m, List * @param property The codegen representation of the OAS schema's property. */ protected void addImportsForPropertyType(CodegenModel model, CodegenProperty property) { - // TODO revise the logic to include map if (property.isContainer) { - addImport(model, typeMapping.get("array")); - } - - addImport(model, property.baseType); - CodegenProperty innerCp = property; - while (innerCp != null) { - addImport(model, innerCp.complexType); - innerCp = innerCp.items; + addImport(model.imports, typeMapping.get("array")); } + addImports(model, property); } /** @@ -6727,6 +6740,9 @@ protected LinkedHashMap getContent(Content content, Se CodegenProperty schemaProp = fromProperty(toMediaTypeSchemaName(contentType, mediaTypeSchemaSuffix), mt.getSchema()); CodegenMediaType codegenMt = new CodegenMediaType(schemaProp, ceMap); cmtContent.put(contentType, codegenMt); + if (schemaProp != null) { + addImports(imports, schemaProp.getImports(false)); + } } return cmtContent; } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java index eb95821d6f3c..187e3f5a14a1 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java @@ -1,6 +1,10 @@ package org.openapitools.codegen; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Stream; import io.swagger.v3.oas.models.media.Schema; import org.openapitools.codegen.utils.ModelUtils; @@ -213,4 +217,51 @@ default void setTypeProperties(Schema p) { setIsAnyType(true); } } + + /** + * @return basic type - no generics supported. + */ + default String getBaseType() { + return null; + }; + + /** + * @return complex type that can contain type parameters - like {@code List} for Java + */ + default String getComplexType() { + return getBaseType(); + }; + + /** + * Recursively collect all necessary imports to include so that the type may be resolved. + * + * @param includeContainerTypes whether or not to include the container types in the returned imports. + * @return all of the imports + */ + default Set getImports(boolean includeContainerTypes) { + Set imports = new HashSet<>(); + if (this.getComposedSchemas() != null) { + CodegenComposedSchemas composed = (CodegenComposedSchemas) this.getComposedSchemas(); + List allOfs = composed.getAllOf() == null ? Collections.emptyList() : composed.getAllOf(); + List oneOfs = composed.getOneOf() == null ? Collections.emptyList() : composed.getOneOf(); + Stream innerTypes = Stream.concat(allOfs.stream(), oneOfs.stream()); + innerTypes.flatMap(cp -> cp.getImports(includeContainerTypes).stream()).forEach(s -> imports.add(s)); + } else if (includeContainerTypes || !(this.getIsArray() || this.getIsMap())) { + // this is our base case, add imports for referenced schemas + // this can't be broken out as a separate if block because Typescript only generates union types as A | B + // and would need to handle this differently + imports.add(this.getComplexType()); + imports.add(this.getBaseType()); + } + if (this.getItems() !=null && this.getIsArray()) { + imports.addAll(this.getItems().getImports(includeContainerTypes)); + } + if (this.getAdditionalProperties() != null) { + imports.addAll(this.getAdditionalProperties().getImports(includeContainerTypes)); + } + if (this.getVars() != null && !this.getVars().isEmpty()) { + this.getVars().stream().flatMap(v -> v.getImports(includeContainerTypes).stream()).forEach(s -> imports.add(s)); + } + return imports; + } } \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java index 54a2b0d20530..4e9fcd6397b4 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java @@ -56,6 +56,16 @@ public class DefaultCodegenTest { + @Test + public void testDeeplyNestedAdditionalPropertiesImports() { + final DefaultCodegen codegen = new DefaultCodegen(); + final OpenAPI openApi = TestUtils.parseFlattenSpec("src/test/resources/3_0/additional-properties-deeply-nested.yaml"); + codegen.setOpenAPI(openApi); + PathItem path = openApi.getPaths().get("/ping"); + CodegenOperation operation = codegen.fromOperation("/ping", "post", path.getPost(), path.getServers()); + Assert.assertEquals(Sets.intersection(operation.imports, Sets.newHashSet("Person")).size(), 1); + } + @Test public void testHasBodyParameter() { final Schema refSchema = new Schema<>().$ref("#/components/schemas/Pet"); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/TypeScriptClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/TypeScriptClientCodegenTest.java index 350af16ebb80..55c7b3b5efaa 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/TypeScriptClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/TypeScriptClientCodegenTest.java @@ -1,7 +1,10 @@ package org.openapitools.codegen.typescript; +import com.google.common.collect.Sets; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.media.*; +import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.TestUtils; import org.openapitools.codegen.languages.TypeScriptClientCodegen; import org.openapitools.codegen.utils.ModelUtils; @@ -41,4 +44,14 @@ public void getTypeDeclarationTest() { Assert.assertEquals(codegen.getTypeDeclaration(parentSchema), "{ [key: string]: Child; }"); } + @Test + public void testComposedSchemasImportTypesIndividually() { + final TypeScriptClientCodegen codegen = new TypeScriptClientCodegen(); + final OpenAPI openApi = TestUtils.parseFlattenSpec("src/test/resources/3_0/composed-schemas.yaml"); + codegen.setOpenAPI(openApi); + PathItem path = openApi.getPaths().get("/pets"); + CodegenOperation operation = codegen.fromOperation("/pets", "patch", path.getPatch(), path.getServers()); + Assert.assertEquals(operation.imports, Sets.newHashSet("Cat", "Dog")); + } + } diff --git a/modules/openapi-generator/src/test/resources/3_0/additional-properties-deeply-nested.yaml b/modules/openapi-generator/src/test/resources/3_0/additional-properties-deeply-nested.yaml new file mode 100644 index 000000000000..78d9c95b54a3 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/additional-properties-deeply-nested.yaml @@ -0,0 +1,32 @@ +openapi: 3.0.1 +info: + title: Test additional properties with ref + version: '1.0' +servers: + - url: 'http://localhost:8000/' +paths: + /ping: + post: + operationId: pingGet + responses: + default: + description: default response + content: + application/json: + schema: + type: object + additionalProperties: + type: object + additionalProperties: + type: object + additionalProperties: + "$ref": "#/components/schemas/Person" +components: + schemas: + Person: + type: object + properties: + lastName: + type: string + firstName: + type: string \ No newline at end of file diff --git a/samples/openapi3/client/petstore/python-experimental/petstore_api/model/mixed_properties_and_additional_properties_class.py b/samples/openapi3/client/petstore/python-experimental/petstore_api/model/mixed_properties_and_additional_properties_class.py index e8bb843a7c89..6f95ff0eaaf1 100644 --- a/samples/openapi3/client/petstore/python-experimental/petstore_api/model/mixed_properties_and_additional_properties_class.py +++ b/samples/openapi3/client/petstore/python-experimental/petstore_api/model/mixed_properties_and_additional_properties_class.py @@ -113,3 +113,5 @@ def __new__( _instantiation_metadata=_instantiation_metadata, **kwargs, ) + +from petstore_api.model.animal import Animal