diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java index e5f4b90614a5..7d2a1d9d5154 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java @@ -769,7 +769,8 @@ public String apiFileFolder() { public String getTypeDeclaration(Schema p) { if (ModelUtils.isArraySchema(p)) { Schema inner = ModelUtils.getSchemaItems(p); - return ModelUtils.isSet(p) ? "Set<" + getTypeDeclaration(inner) + ">" : "[" + getTypeDeclaration(inner) + "]"; + String innerTypeDeclaration = getItemsTypeDeclaration(inner); + return ModelUtils.isSet(p) ? "Set<" + innerTypeDeclaration + ">" : "[" + innerTypeDeclaration + "]"; } else if (ModelUtils.isMapSchema(p)) { Schema inner = ModelUtils.getAdditionalProperties(p); return "[String: " + getTypeDeclaration(inner) + "]"; @@ -777,6 +778,13 @@ public String getTypeDeclaration(Schema p) { return super.getTypeDeclaration(p); } + private String getItemsTypeDeclaration(Schema items) { + String itemsTypeDeclaration = getTypeDeclaration(items); + Schema itemsSchema = ModelUtils.getReferencedSchema(openAPI, unaliasSchema(items)); + String nullable = ModelUtils.isNullable(itemsSchema) && !itemsTypeDeclaration.endsWith("?") ? "?" : ""; + return itemsTypeDeclaration + nullable; + } + @Override public String getSchemaType(Schema p) { String openAPIType = super.getSchemaType(p); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java index 3af8f6805235..7cd975547f2c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java @@ -815,7 +815,8 @@ public String apiFileFolder() { public String getTypeDeclaration(Schema p) { if (ModelUtils.isArraySchema(p)) { Schema inner = ModelUtils.getSchemaItems(p); - return ModelUtils.isSet(p) ? "Set<" + getTypeDeclaration(inner) + ">" : "[" + getTypeDeclaration(inner) + "]"; + String innerTypeDeclaration = getItemsTypeDeclaration(inner); + return ModelUtils.isSet(p) ? "Set<" + innerTypeDeclaration + ">" : "[" + innerTypeDeclaration + "]"; } else if (ModelUtils.isMapSchema(p)) { Schema inner = unaliasSchema(ModelUtils.getAdditionalProperties(p)); return "[String: " + getItemsTypeDeclaration(inner) + "]"; @@ -825,7 +826,8 @@ public String getTypeDeclaration(Schema p) { private String getItemsTypeDeclaration(Schema items) { String itemsTypeDeclaration = getTypeDeclaration(items); - String nullable = items.getNullable() != null && items.getNullable() && !itemsTypeDeclaration.endsWith("?") ? "?" : ""; + Schema itemsSchema = ModelUtils.getReferencedSchema(openAPI, unaliasSchema(items)); + String nullable = ModelUtils.isNullable(itemsSchema) && !itemsTypeDeclaration.endsWith("?") ? "?" : ""; return itemsTypeDeclaration + nullable; } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java index 8344a0427b76..ec64a91269d1 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java @@ -410,4 +410,35 @@ public void testAdditionalModelImportsParsing() { Assert.assertEquals(imports.get(2), "BazKit"); } + @Test(description = "nullable array items are declared as optionals", enabled = true) + public void nullableArrayItemsTest() { + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_22355.yaml"); + final DefaultCodegen codegen = new Swift5ClientCodegen(); + codegen.setOpenAPI(openAPI); + final String model = "NullItemsNotNullItems"; + final CodegenModel cm = codegen.fromModel(model, openAPI.getComponents().getSchemas().get(model)); + + Assert.assertEquals(cm.vars.size(), 9); + + Assert.assertEquals(cm.vars.get(0).baseName, "nullableItems"); + Assert.assertEquals(cm.vars.get(1).baseName, "notNullableItems"); + Assert.assertEquals(cm.vars.get(2).baseName, "defaultItems"); + Assert.assertEquals(cm.vars.get(3).baseName, "nullableDoubleItems"); + Assert.assertEquals(cm.vars.get(4).baseName, "xNullableItems"); + Assert.assertEquals(cm.vars.get(5).baseName, "aliasedNullableItems"); + Assert.assertEquals(cm.vars.get(6).baseName, "nullableItemsSet"); + Assert.assertEquals(cm.vars.get(7).baseName, "nestedNullableItems"); + Assert.assertEquals(cm.vars.get(8).baseName, "modelRefNullableItems"); + + Assert.assertEquals(cm.vars.get(0).dataType, "[String?]"); + Assert.assertEquals(cm.vars.get(1).dataType, "[String]"); + Assert.assertEquals(cm.vars.get(2).dataType, "[String]"); + Assert.assertEquals(cm.vars.get(3).dataType, "[Double?]"); + Assert.assertEquals(cm.vars.get(4).dataType, "[String?]"); + Assert.assertEquals(cm.vars.get(5).dataType, "[String?]"); + Assert.assertEquals(cm.vars.get(6).dataType, "Set"); + Assert.assertEquals(cm.vars.get(7).dataType, "[[String?]]"); + Assert.assertEquals(cm.vars.get(8).dataType, "[NullablePet?]"); + } + } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java index ad5ee6eb8c93..dfd3cd8796ac 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java @@ -505,4 +505,34 @@ public void testNullableMap() { Assert.assertEquals(notNullableMap.getDataType(), "[String: String]"); Assert.assertEquals(defaultMap.getDataType(), "[String: String]"); } + + @Test(description = "Issue #22355") + public void testNullableArrayItems() { + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/swift6/issue22355-nullable-array-items.yaml"); + final DefaultCodegen codegen = new Swift6ClientCodegen(); + codegen.setOpenAPI(openAPI); + + Schema test1 = openAPI.getComponents().getSchemas().get("NullItemsNotNullItems"); + CodegenModel cm1 = codegen.fromModel("NullItemsNotNullItems", test1); + + // Assert the dataType properly generated + CodegenProperty nullableItems = cm1.vars.get(0); + CodegenProperty notNullableItems = cm1.vars.get(1); + CodegenProperty defaultItems = cm1.vars.get(2); + CodegenProperty nullableDoubleItems = cm1.vars.get(3); + CodegenProperty xNullableItems = cm1.vars.get(4); + CodegenProperty aliasedNullableItems = cm1.vars.get(5); + CodegenProperty nullableItemsSet = cm1.vars.get(6); + CodegenProperty nestedNullableItems = cm1.vars.get(7); + CodegenProperty modelRefNullableItems = cm1.vars.get(8); + Assert.assertEquals(nullableItems.getDataType(), "[String?]"); + Assert.assertEquals(notNullableItems.getDataType(), "[String]"); + Assert.assertEquals(defaultItems.getDataType(), "[String]"); + Assert.assertEquals(nullableDoubleItems.getDataType(), "[Double?]"); + Assert.assertEquals(xNullableItems.getDataType(), "[String?]"); + Assert.assertEquals(aliasedNullableItems.getDataType(), "[String?]"); + Assert.assertEquals(nullableItemsSet.getDataType(), "Set"); + Assert.assertEquals(nestedNullableItems.getDataType(), "[[String?]]"); + Assert.assertEquals(modelRefNullableItems.getDataType(), "[NullablePet?]"); + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_22355.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_22355.yaml new file mode 100644 index 000000000000..ac92095767d5 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/issue_22355.yaml @@ -0,0 +1,63 @@ +openapi: 3.0.0 +info: + title: 'Issue 22355 Nullable array items' + version: latest +components: + schemas: + NullItemsNotNullItems: + properties: + nullableItems: + type: array + items: + type: string + nullable: true + notNullableItems: + type: array + items: + type: string + nullable: false + defaultItems: + type: array + items: + type: string + nullableDoubleItems: + type: array + items: + type: number + format: double + nullable: true + xNullableItems: + type: array + items: + type: string + x-nullable: true + aliasedNullableItems: + type: array + items: + $ref: '#/components/schemas/NullableString' + nullableItemsSet: + type: array + uniqueItems: true + items: + type: string + nullable: true + nestedNullableItems: + type: array + items: + type: array + items: + type: string + nullable: true + modelRefNullableItems: + type: array + items: + $ref: '#/components/schemas/NullablePet' + NullableString: + type: string + nullable: true + NullablePet: + type: object + nullable: true + properties: + name: + type: string diff --git a/modules/openapi-generator/src/test/resources/3_0/swift6/issue22355-nullable-array-items.yaml b/modules/openapi-generator/src/test/resources/3_0/swift6/issue22355-nullable-array-items.yaml new file mode 100644 index 000000000000..ac92095767d5 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/swift6/issue22355-nullable-array-items.yaml @@ -0,0 +1,63 @@ +openapi: 3.0.0 +info: + title: 'Issue 22355 Nullable array items' + version: latest +components: + schemas: + NullItemsNotNullItems: + properties: + nullableItems: + type: array + items: + type: string + nullable: true + notNullableItems: + type: array + items: + type: string + nullable: false + defaultItems: + type: array + items: + type: string + nullableDoubleItems: + type: array + items: + type: number + format: double + nullable: true + xNullableItems: + type: array + items: + type: string + x-nullable: true + aliasedNullableItems: + type: array + items: + $ref: '#/components/schemas/NullableString' + nullableItemsSet: + type: array + uniqueItems: true + items: + type: string + nullable: true + nestedNullableItems: + type: array + items: + type: array + items: + type: string + nullable: true + modelRefNullableItems: + type: array + items: + $ref: '#/components/schemas/NullablePet' + NullableString: + type: string + nullable: true + NullablePet: + type: object + nullable: true + properties: + name: + type: string