From b0f7708296fde37782962e2a3274d142703b5b18 Mon Sep 17 00:00:00 2001 From: lnash94 Date: Fri, 21 Jan 2022 14:26:41 +0530 Subject: [PATCH] Add fix for nullable record array scenarios --- .../service/OpenAPIComponentMapper.java | 45 +++++--- .../expected_gen/record/cyclic_record.yaml | 105 ++++++++++++++++++ .../record/cyclic_record.bal | 36 ++++++ 3 files changed, 172 insertions(+), 14 deletions(-) diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java index 188e1a7f1..71ae47bfd 100644 --- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java +++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java @@ -321,21 +321,11 @@ private void mapArrayToArraySchema(Map schema, RecordFieldSymbol Schema symbolProperty = ConverterCommonUtils.getOpenApiSchema(symbol.typeKind().getName()); // Handle record fields have union type array (ex: string[]? name) if (symbol.typeKind() == TypeDescKind.UNION) { - symbolProperty = getSchemaForUnionType((UnionTypeSymbol) symbol, symbolProperty); + symbolProperty = getSchemaForUnionType((UnionTypeSymbol) symbol, symbolProperty, componentName, schema); } // Set the record model to the definition if (symbol.typeKind().equals(TypeDescKind.TYPE_REFERENCE)) { - if (((TypeReferenceTypeSymbol) symbol).definition().kind() == SymbolKind.ENUM) { - TypeReferenceTypeSymbol typeRefEnum = (TypeReferenceTypeSymbol) symbol; - EnumSymbol enumSymbol = (EnumSymbol) typeRefEnum.definition(); - symbolProperty = mapEnumValues(enumSymbol); - } else { - symbolProperty.set$ref(symbol.getName().orElseThrow().trim()); - TypeReferenceTypeSymbol typeRecord = (TypeReferenceTypeSymbol) symbol; - if (!isSameRecord(componentName, typeRecord)) { - createComponentSchema(schema, typeRecord); - } - } + symbolProperty = getSchemaForTypeReferenceSymbol(symbol, symbolProperty, componentName, schema); } // Handle nested array type if (arrayDimensions > 1) { @@ -352,12 +342,18 @@ private void mapArrayToArraySchema(Map schema, RecordFieldSymbol * `string[]? name` here it takes union member types as array and nil,fix should do with array type and map to * oneOf OAS. */ - private Schema getSchemaForUnionType(UnionTypeSymbol symbol, Schema symbolProperty) { + private Schema getSchemaForUnionType(UnionTypeSymbol symbol, Schema symbolProperty, String componentName, + Map schema) { List typeSymbols = symbol.userSpecifiedMemberTypes(); for (TypeSymbol typeSymbol: typeSymbols) { if (typeSymbol.typeKind() == TypeDescKind.ARRAY) { TypeSymbol arrayType = ((ArrayTypeSymbol) typeSymbol).memberTypeDescriptor(); - symbolProperty = ConverterCommonUtils.getOpenApiSchema(arrayType.typeKind().getName()); + // Set the record model to the definition + if (arrayType.typeKind().equals(TypeDescKind.TYPE_REFERENCE)) { + symbolProperty = getSchemaForTypeReferenceSymbol(arrayType, symbolProperty, componentName, schema); + } else { + symbolProperty = ConverterCommonUtils.getOpenApiSchema(arrayType.typeKind().getName()); + } } else if (typeSymbol.typeKind() != TypeDescKind.NIL) { symbolProperty = ConverterCommonUtils.getOpenApiSchema(typeSymbol.typeKind().getName()); } @@ -365,6 +361,27 @@ private Schema getSchemaForUnionType(UnionTypeSymbol symbol, Schema symbolProper return symbolProperty; } + /** + * This util function is to handle the type reference symbol is record type or enum type. + * + */ + private Schema getSchemaForTypeReferenceSymbol(TypeSymbol arrayType, Schema symbolProperty, String componentName, + Map schema) { + + if (((TypeReferenceTypeSymbol) arrayType).definition().kind() == SymbolKind.ENUM) { + TypeReferenceTypeSymbol typeRefEnum = (TypeReferenceTypeSymbol) arrayType; + EnumSymbol enumSymbol = (EnumSymbol) typeRefEnum.definition(); + symbolProperty = mapEnumValues(enumSymbol); + } else { + symbolProperty.set$ref(arrayType.getName().orElseThrow().trim()); + TypeReferenceTypeSymbol typeRecord = (TypeReferenceTypeSymbol) arrayType; + if (!isSameRecord(componentName, typeRecord)) { + createComponentSchema(schema, typeRecord); + } + } + return symbolProperty; + } + /** * Handle nested array. */ diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/record/cyclic_record.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/record/cyclic_record.yaml index 7f9860f3f..da66ec3ca 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/record/cyclic_record.yaml +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/record/cyclic_record.yaml @@ -46,6 +46,54 @@ paths: $ref: '#/components/schemas/ResponseError03' "202": description: Accepted + /pet04: + post: + operationId: operation_post_/pet04 + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseError04' + "202": + description: Accepted + /pet05: + post: + operationId: operation_post_/pet05 + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseError05' + "202": + description: Accepted + /pet06: + post: + operationId: operation_post_/pet06 + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseError06' + "202": + description: Accepted + /pet07: + post: + operationId: operation_post_/pet07 + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseError07' + "202": + description: Accepted components: schemas: ResponseError: @@ -85,3 +133,60 @@ components: type: array items: $ref: '#/components/schemas/ResponseError03' + ResponseError04: + required: + - id + type: object + properties: + id: + type: integer + format: int32 + nullable: true + resError: + type: array + items: + type: array + items: + $ref: '#/components/schemas/ResponseError04' + ResponseError05: + required: + - id + type: object + properties: + id: + type: integer + format: int32 + nullable: true + resError: + nullable: true + oneOf: + - $ref: '#/components/schemas/ResponseError05' + ResponseError06: + required: + - id + type: object + properties: + id: + type: integer + format: int32 + nullable: true + resError: + type: array + nullable: true + items: + $ref: '#/components/schemas/ResponseError06' + ResponseError07: + required: + - id + - resError + type: object + properties: + id: + type: integer + format: int32 + nullable: true + resError: + type: array + nullable: true + items: + $ref: '#/components/schemas/ResponseError07' diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/record/cyclic_record.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/record/cyclic_record.bal index dc6e3a6f9..306508575 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/record/cyclic_record.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/record/cyclic_record.bal @@ -15,6 +15,26 @@ type ResponseError03 record {| ResponseError03[] resError?; |}; +type ResponseError04 record {| + int? id; + ResponseError04[][] resError?; +|}; + +type ResponseError05 record {| + int? id; + ResponseError05? resError?; +|}; + +type ResponseError06 record {| + int? id; + ResponseError06[]? resError?; +|}; + +type ResponseError07 record {| + int? id; + ResponseError07[]? resError; +|}; + listener http:Listener ep0 = new (443, config = {host: "petstore.swagger.io"}); service /payloadV on ep0 { @@ -30,4 +50,20 @@ service /payloadV on ep0 { http:Accepted accept = {body: ()}; return accept; } + resource function post pet04() returns ResponseError04|http:Accepted { + http:Accepted accept = {body: ()}; + return accept; + } + resource function post pet05() returns ResponseError05|http:Accepted { + http:Accepted accept = {body: ()}; + return accept; + } + resource function post pet06() returns ResponseError06|http:Accepted { + http:Accepted accept = {body: ()}; + return accept; + } + resource function post pet07() returns ResponseError07|http:Accepted { + http:Accepted accept = {body: ()}; + return accept; + } }