From 7d6dfca326663cdea47905fa240742d21a4f7348 Mon Sep 17 00:00:00 2001 From: lnash94 Date: Thu, 14 Dec 2023 14:22:31 +0530 Subject: [PATCH 01/85] Resolve conflicts --- .../openapi/cmd/BallerinaCodeGenerator.java | 2 +- .../openapi/cmd/OpenApiGenServiceCmdTest.java | 32 ++++++++ .../expected_gen/without-data-binding.bal | 11 +++ .../test/resources/withoutDataBinding.yaml | 76 +++++++++++++++++++ .../openapi/core/GeneratorUtils.java | 47 ++++++++++-- .../client/BallerinaClientGenerator.java | 3 +- .../service/BallerinaServiceGenerator.java | 5 +- 7 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 openapi-cli/src/test/resources/expected_gen/without-data-binding.bal create mode 100644 openapi-cli/src/test/resources/withoutDataBinding.yaml diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java index cbbcca05e..420316d5b 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java @@ -441,7 +441,7 @@ public List generateBallerinaService(Path openAPI, String serviceNam openAPIDef, nullable, preGeneratedTypeDefNodes); String schemaContent = Formatter.format( ballerinaSchemaGenerator.generateSyntaxTree()).toSourceCode(); - if (!schemaContent.isBlank()) { + if (!schemaContent.isBlank() && !generateWithoutDataBinding) { sourceFiles.add(new GenSrcFile(GenSrcFile.GenFileType.GEN_SRC, srcPackage, TYPE_FILE_NAME, (licenseHeader.isBlank() ? DEFAULT_FILE_HEADER : licenseHeader) + schemaContent)); } diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java b/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java index c8765cfab..adb5c195d 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java @@ -17,8 +17,10 @@ */ package io.ballerina.openapi.cmd; +import io.ballerina.cli.launcher.BLauncherException; import org.testng.Assert; import org.testng.annotations.Test; +import picocli.CommandLine; import java.io.IOException; import java.nio.file.Files; @@ -111,4 +113,34 @@ public void testOneOfSchemaGen() throws IOException { Assert.fail("Service generation for OneOf Schema type failed."); } } + + @Test(description = "Test for --without-data-binding flag") + public void testWithoutDataBinding() throws IOException { + Path yamlPath = resourceDir.resolve(Paths.get("withoutDataBinding.yaml")); + String[] args = {"--input", yamlPath.toString(), "--without-data-binding", "-o", + this.tmpDir.toString(), "--mode", "service"}; + OpenApiCmd cmd = new OpenApiCmd(printStream, this.tmpDir); + new CommandLine(cmd).parseArgs(args); + String output = ""; + try { + cmd.execute(); + } catch (BLauncherException e) { + output = e.getDetailedMessages().get(0); + } + + Path expectedServiceFile = resourceDir.resolve(Paths.get("expected_gen", + "without-data-binding.bal")); + Stream expectedServiceLines = Files.lines(expectedServiceFile); + String expectedService = expectedServiceLines.collect(Collectors.joining("\n")); + expectedServiceLines.close(); + Assert.assertFalse(Files.exists(this.tmpDir.resolve("types.bal"))); + if (Files.exists(this.tmpDir.resolve("withoutdatabinding_service.bal"))) { + String generatedService = getStringFromFile(this.tmpDir.resolve("withoutdatabinding_service.bal")); + Assert.assertEquals(replaceWhiteSpace(generatedService), replaceWhiteSpace(expectedService), + "Expected content and actual generated content is mismatched for: " + yamlPath); + deleteGeneratedFiles("without-data-binding-service.bal"); + } else { + Assert.fail("Service generation for All Of Schema type failed."); + } + } } diff --git a/openapi-cli/src/test/resources/expected_gen/without-data-binding.bal b/openapi-cli/src/test/resources/expected_gen/without-data-binding.bal new file mode 100644 index 000000000..bf56b7a0a --- /dev/null +++ b/openapi-cli/src/test/resources/expected_gen/without-data-binding.bal @@ -0,0 +1,11 @@ +// AUTO-GENERATED FILE. +// This file is auto-generated by the Ballerina OpenAPI tool. + +import ballerina/http; + +listener http:Listener ep0 = new (9090, config = {host: "localhost"}); + +service /v1 on ep0 { + resource function get coupons/[string couponCode]/[int id]/[string limits](http:Caller caller, http:Request request) returns error? { + } +} diff --git a/openapi-cli/src/test/resources/withoutDataBinding.yaml b/openapi-cli/src/test/resources/withoutDataBinding.yaml new file mode 100644 index 000000000..029d20c3a --- /dev/null +++ b/openapi-cli/src/test/resources/withoutDataBinding.yaml @@ -0,0 +1,76 @@ +openapi: 3.0.1 +info: + title: V1 + version: 0.1.0 +servers: + - url: "{server}:{port}/v1" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /coupons/{couponCode}/{id}/{limits}: + get: + operationId: getCoupon + parameters: + - $ref: '#/components/parameters/ngwCouponCodePathParam' + - $ref: '#/components/parameters/ngwCouponCodePathParam02' + - $ref: '#/components/parameters/ngwCouponCodePathParam03' + responses: + '200': + description: Successful operation, coupon was found by requested code + content: + application/json: + schema: + $ref: '#/components/schemas/Cat' +components: + parameters: + ngwCouponCodePathParam: + in: path + name: couponCode + required: true + schema: + $ref: '#/components/schemas/Coupon' + ngwCouponCodePathParam02: + in: path + name: id + required: true + schema: + $ref: '#/components/schemas/Id' + ngwCouponCodePathParam03: + in: path + name: limits + required: true + schema: + type: array + items: + type: integer + schemas: + Coupon: + type: string + Id: + $ref: '#/components/schemas/AddressNo' + AddressNo: + type: integer + Pet: + type: object + properties: + name: + type: string + tag: + type: string + required: + - name + - tag + Cat: + type: object + properties: + name: + type: string + parent: + $ref: '#/components/schemas/Pet' + petType: + $ref: '#/components/schemas/Cat' + required: + - name diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java index dc0facb62..ed27f0eb3 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java @@ -221,7 +221,8 @@ public static QualifiedNameReferenceNode getQualifiedNameReferenceNode(String mo * @return - node lists * @throws BallerinaOpenApiException */ - public static List getRelativeResourcePath(String path, Operation operation, List resourceFunctionDocs) + public static List getRelativeResourcePath(String path, Operation operation, List resourceFunctionDocs, + Components components, boolean isWithoutDataBinding) throws BallerinaOpenApiException { List functionRelativeResourcePath = new ArrayList<>(); @@ -241,7 +242,7 @@ public static List getRelativeResourcePath(String path, Operation operatio */ if (operation.getParameters() != null) { extractPathParameterDetails(operation, functionRelativeResourcePath, pathNode, - pathParam, resourceFunctionDocs); + pathParam, resourceFunctionDocs, components, isWithoutDataBinding); } } else if (!pathNode.isBlank()) { IdentifierToken idToken = createIdentifierToken(escapeIdentifier(pathNode.trim())); @@ -261,7 +262,9 @@ public static List getRelativeResourcePath(String path, Operation operatio } private static void extractPathParameterDetails(Operation operation, List functionRelativeResourcePath, - String pathNode, String pathParam, List resourceFunctionDocs) + String pathNode, String pathParam, + List resourceFunctionDocs, + Components components, boolean isWithoutDataBinding) throws BallerinaOpenApiException { // check whether path parameter segment has special character String[] split = pathNode.split(CLOSE_CURLY_BRACE, 2); @@ -281,9 +284,10 @@ private static void extractPathParameterDetails(Operation operation, List && parameter.getIn().equals("path")) { String paramType; if (parameter.getSchema().get$ref() != null) { - paramType = getValidName(extractReferenceType(parameter.getSchema().get$ref()), true); + paramType = resolveReferenceType(parameter.getSchema(), components, isWithoutDataBinding, + pathParam); } else { - paramType = convertOpenAPITypeToBallerina(parameter.getSchema()); + paramType = getPathParameterType(parameter.getSchema(), pathParam); if (paramType.endsWith(NILLABLE)) { throw new BallerinaOpenApiException("Path parameter value cannot be null."); } @@ -1102,4 +1106,37 @@ public static boolean isIntegerSchema(Schema fieldSchema) { public static boolean isNumberSchema(Schema fieldSchema) { return Objects.equals(GeneratorUtils.getOpenAPIType(fieldSchema), NUMBER); } + + public static String resolveReferenceType(Schema schema, Components components, boolean isWithoutDataBinding, + String pathParam) throws BallerinaOpenApiException { + String type = GeneratorUtils.extractReferenceType(schema.get$ref()); + + if (isWithoutDataBinding) { + Schema referencedSchema = components.getSchemas().get(getValidName(type, true)); + if (referencedSchema != null) { + if (referencedSchema.get$ref() != null) { + type = resolveReferenceType(referencedSchema, components, isWithoutDataBinding, pathParam); + } else { + type = getPathParameterType(referencedSchema, pathParam); + } + } + } else { + type = getValidName(type, true); + } + return type; + } + + private static String getPathParameterType(Schema typeSchema, String pathParam) + throws BallerinaOpenApiException { + String type; + if (!(isStringSchema(typeSchema) || isNumberSchema(typeSchema) || isBooleanSchema(typeSchema) + || isIntegerSchema(typeSchema))) { + type = "string"; + LOGGER.warn("unsupported path parameter type found in the parameter `" + pathParam + "`. hence the " + + "parameter type is set to string."); + } else { + type = GeneratorUtils.convertOpenAPITypeToBallerina(typeSchema); + } + return type; + } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java index f34a83f4d..47aa8b535 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java @@ -580,7 +580,8 @@ private FunctionDefinitionNode getClientMethodFunctionDefinitionNode(List relativeResourcePath = resourceMode ? - createNodeList(GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), null)) : + createNodeList(GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), + null, openAPI.getComponents(), false)) : createEmptyNodeList(); return createFunctionDefinitionNode(null, metadataNode, qualifierList, functionKeyWord, functionName, relativeResourcePath, diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java index 3de6ec406..c3393a31c 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java @@ -247,7 +247,8 @@ private List applyFiltersForOperations(Filter filter, String path, filterOperations.contains(operation.getValue().getOperationId().trim()))) { // getRelative resource path List functionRelativeResourcePath = GeneratorUtils.getRelativeResourcePath(path, - operation.getValue(), resourceFunctionDocs); + operation.getValue(), resourceFunctionDocs, openAPI.getComponents(), + generateWithoutDataBinding); // function call FunctionDefinitionNode functionDefinitionNode = generateWithoutDataBinding ? @@ -261,7 +262,7 @@ private List applyFiltersForOperations(Filter filter, String path, } else { // getRelative resource path List relativeResourcePath = GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), - resourceFunctionDocs); + resourceFunctionDocs, openAPI.getComponents(), generateWithoutDataBinding); // function call FunctionDefinitionNode resourceFunction = generateWithoutDataBinding ? generateGenericResourceFunctions(operation, From 0a9443187460a7fc53c06dbeefa5b9c8f0144e3f Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 3 Jan 2024 15:10:24 +0530 Subject: [PATCH 02/85] Initial commit --- .../service/mapper/hateoas/HateoasMapper.java | 40 +++++++ .../mapper/model/ServiceNodeVisitor.java | 104 ++++++++++++++++++ .../mapper/parameter/ResponseMapper.java | 9 ++ .../generators/openapi/HateoasTests.java | 34 ++++++ .../hateoas/hateoas_automatic_linking.yaml | 87 +++++++++++++++ .../hateoas/hateoas_automatic_linking.bal | 40 +++++++ openapi-cli/src/test/resources/testng.xml | 1 + 7 files changed, 315 insertions(+) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java create mode 100644 openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_automatic_linking.yaml create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java new file mode 100644 index 000000000..6ab7d9d4d --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.ballerina.openapi.service.mapper.hateoas; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; +import io.ballerina.openapi.service.mapper.model.ServiceNodeVisitor; +import io.swagger.v3.oas.models.OpenAPI; + +import java.util.List; + +public class HateoasMapper { + + private final SemanticModel semanticModel; + private final ServiceNodeVisitor serviceNodeVisitor; + + public HateoasMapper(SemanticModel semanticModel, ServiceNodeVisitor serviceNodeVisitor) { + this.semanticModel = semanticModel; + this.serviceNodeVisitor = serviceNodeVisitor; + } + +// public void mapHateoasLinks() { +// +// } +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java new file mode 100644 index 000000000..e61e56b31 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.model; + +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.NodeVisitor; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.ballerina.compiler.syntax.tree.AnnotationNode; +import io.ballerina.compiler.syntax.tree.SpecificFieldNode; +import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.compiler.syntax.tree.Node; +//import io.swagger.v3.oas.models.links.Link; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Visitor to get the ServiceDeclarationNode. + * + */ +public class ServiceNodeVisitor extends NodeVisitor { + + public Map>> resourceMap = new HashMap<>(); +// private String resourceName; +// private String method; +// private String operationId; + + @Override + public void visit(ServiceDeclarationNode serviceDeclarationNode) { + for (Node child : serviceDeclarationNode.children()) { + if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { + child.accept(this); + } + } + System.out.println(resourceMap); + } + + @Override + public void visit(FunctionDefinitionNode functionDefinitionNode) { + for (Node child : functionDefinitionNode.children()) { + if (SyntaxKind.METADATA.equals(child.kind())) { + child.accept(this); + } + } + } + + @Override + public void visit(MetadataNode metadataNode) { + metadataNode.children().get(0).accept(this); + } + + @Override + public void visit(AnnotationNode annotationNode) { + for (Node child : annotationNode.children()) { + if (SyntaxKind.MAPPING_CONSTRUCTOR.equals(child.kind())) { + child.accept(this); + } + } + } + + @Override + public void visit(MappingConstructorExpressionNode mappingConstructorExpressionNode) { + for (Node child : mappingConstructorExpressionNode.children()) { + if (SyntaxKind.SPECIFIC_FIELD.equals(child.kind())) { + child.accept(this); + } + } + } + + @Override + public void visit(SpecificFieldNode specificFieldNode) { + if (SyntaxKind.STRING_LITERAL.equals(specificFieldNode.children().get(2).kind())) { +// resourceName = specificFieldNode.children().get(2).toString().replace("\"",""); + } else { + specificFieldNode.children().get(2).accept(this); + } + } + + @Override + public void visit(ListConstructorExpressionNode listConstructorExpressionNode) { +// resourceLink = listConstructorExpressionNode.children().get(1); +// resourceMap.put(resourceName, resourceLink); + } +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java index ddb9645f1..4410352a5 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java @@ -35,8 +35,10 @@ import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; import io.ballerina.openapi.service.mapper.AdditionalData; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; +//import io.ballerina.openapi.service.mapper.hateoas.HateoasMapper; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OperationAdaptor; +//import io.ballerina.openapi.service.mapper.model.ServiceNodeVisitor; import io.ballerina.openapi.service.mapper.parameter.model.CacheConfigAnnotation; import io.ballerina.openapi.service.mapper.parameter.utils.CacheHeaderUtils; import io.ballerina.openapi.service.mapper.parameter.utils.MediaTypeUtils; @@ -46,6 +48,7 @@ import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.headers.Header; +//import io.swagger.v3.oas.models.links.Link; import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.Content; import io.swagger.v3.oas.models.media.MediaType; @@ -210,6 +213,11 @@ private void addResponseContent(TypeSymbol returnType, ApiResponse apiResponse, } } +// private void addResponseLinks(ApiResponse apiResponse, ServiceNodeVisitor serviceNodeVisitor) { +// HateoasMapper hateoasMapper = new HateoasMapper(semanticModel, serviceNodeVisitor); +// apiResponse.setLinks(serviceNodeVisitor.resourceMap); +// } + public void addApiResponse(ApiResponse apiResponse, String statusCode) { addHeaders(apiResponse, statusCode); if (apiResponses.containsKey(statusCode)) { @@ -287,6 +295,7 @@ private void addResponseMappingForHttpResponse() { ApiResponse apiResponse = new ApiResponse(); apiResponse.setDescription("Any Response"); apiResponse.setContent(new Content().addMediaType("*/*", mediaTypeObj)); +// addResponseLinks(apiResponse, new ServiceNodeVisitor()); addApiResponse(apiResponse, "default"); } diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java new file mode 100644 index 000000000..eaa7c5848 --- /dev/null +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.ballerina.openapi.generators.openapi; + +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class HateoasTests { + private static final Path RES_DIR = Paths.get("src/test/resources/ballerina-to-openapi").toAbsolutePath(); + + @Test(description = "Automatic linking between resoruce functions") + public void testHateoasAutomaticLinking() throws IOException { + Path ballerinafilePath = RES_DIR.resolve("hateoas/hateoas_automatic_linking.bal"); + TestUtils.compareWithGeneratedFile(ballerinafilePath, "hateoas/hateoas_automatic_linking.yaml"); + } +} diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_automatic_linking.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_automatic_linking.yaml new file mode 100644 index 000000000..6b441cb47 --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_automatic_linking.yaml @@ -0,0 +1,87 @@ +openapi: 3.0.1 +info: + title: PayloadV + version: 0.0.0 +servers: + - url: "{server}:{port}/payloadV" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /locations: + get: + operationId: getLocations + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/Location' + links: + room: + operationId: getLocationsIdRooms + /locations/{id}/rooms: + get: + operationId: getLocationsIdRooms + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "202": + description: Accepted + "500": + description: InternalServerError + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' +components: + schemas: + Location: + required: + - address + - id + - name + type: object + properties: + name: + type: string + id: + type: string + address: + type: string + ErrorPayload: + required: + - message + - method + - path + - reason + - status + - timestamp + type: object + properties: + timestamp: + type: string + status: + type: integer + format: int64 + reason: + type: string + message: + type: string + path: + type: string + method: + type: string diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal new file mode 100644 index 000000000..acd75cbff --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal @@ -0,0 +1,40 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +public type Location record { + string name; + string id; + string address; +}; + +service /payloadV on new http:Listener(9090) { + @http:ResourceConfig { + name: "Locations", + linkedTo: [ {name: "Rooms", relation: "room", method: "get"} ] + } + resource function get locations() returns Location { + return {name: "Cinnamon Lodge", id: "1001", address: "Habarana"}; + } + + @http:ResourceConfig { + name: "Rooms" + } + resource function get locations/[string id]/rooms() returns error? { + return; + } +} diff --git a/openapi-cli/src/test/resources/testng.xml b/openapi-cli/src/test/resources/testng.xml index b70c7e5b3..5273f05fb 100644 --- a/openapi-cli/src/test/resources/testng.xml +++ b/openapi-cli/src/test/resources/testng.xml @@ -47,6 +47,7 @@ under the License. + From 1e4b3e2cbd3fca80b3f363a2de35fd801ebb4fca Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 3 Jan 2024 15:30:38 +0530 Subject: [PATCH 03/85] Fix checkstyle errors --- .../openapi/service/mapper/hateoas/HateoasMapper.java | 4 ---- .../openapi/service/mapper/model/ServiceNodeVisitor.java | 1 - .../openapi/service/mapper/parameter/ResponseMapper.java | 3 --- 3 files changed, 8 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index 6ab7d9d4d..7a8cbcdde 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -18,11 +18,7 @@ package io.ballerina.openapi.service.mapper.hateoas; import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.ServiceNodeVisitor; -import io.swagger.v3.oas.models.OpenAPI; - -import java.util.List; public class HateoasMapper { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java index e61e56b31..29f514b84 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java @@ -28,7 +28,6 @@ import io.ballerina.compiler.syntax.tree.MetadataNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.compiler.syntax.tree.Node; -//import io.swagger.v3.oas.models.links.Link; import java.util.HashMap; import java.util.List; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java index 4410352a5..f19375151 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java @@ -35,10 +35,8 @@ import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; import io.ballerina.openapi.service.mapper.AdditionalData; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; -//import io.ballerina.openapi.service.mapper.hateoas.HateoasMapper; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OperationAdaptor; -//import io.ballerina.openapi.service.mapper.model.ServiceNodeVisitor; import io.ballerina.openapi.service.mapper.parameter.model.CacheConfigAnnotation; import io.ballerina.openapi.service.mapper.parameter.utils.CacheHeaderUtils; import io.ballerina.openapi.service.mapper.parameter.utils.MediaTypeUtils; @@ -48,7 +46,6 @@ import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.headers.Header; -//import io.swagger.v3.oas.models.links.Link; import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.Content; import io.swagger.v3.oas.models.media.MediaType; From 804da50dcbffae95f0f4907bab3f3f47534e3e7f Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 3 Jan 2024 15:37:58 +0530 Subject: [PATCH 04/85] Fix checkstyle errors --- .../mapper/model/ServiceNodeVisitor.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java index 29f514b84..ab7f2bac5 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java @@ -18,20 +18,20 @@ package io.ballerina.openapi.service.mapper.model; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.SpecificFieldNode; -import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; -import io.ballerina.compiler.syntax.tree.Node; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; /** * Visitor to get the ServiceDeclarationNode. @@ -51,7 +51,7 @@ public void visit(ServiceDeclarationNode serviceDeclarationNode) { child.accept(this); } } - System.out.println(resourceMap); +// System.out.println(resourceMap); } @Override From e0403dc079acf152e8a94b162c5fee2ba8882316 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Wed, 3 Jan 2024 16:38:57 +0530 Subject: [PATCH 05/85] Fix checkstyle violations --- .../service/mapper/hateoas/HateoasMapper.java | 36 ------------------- .../mapper/model/ServiceNodeVisitor.java | 19 +++++----- 2 files changed, 9 insertions(+), 46 deletions(-) delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java deleted file mode 100644 index 7a8cbcdde..000000000 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package io.ballerina.openapi.service.mapper.hateoas; - -import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.openapi.service.mapper.model.ServiceNodeVisitor; - -public class HateoasMapper { - - private final SemanticModel semanticModel; - private final ServiceNodeVisitor serviceNodeVisitor; - - public HateoasMapper(SemanticModel semanticModel, ServiceNodeVisitor serviceNodeVisitor) { - this.semanticModel = semanticModel; - this.serviceNodeVisitor = serviceNodeVisitor; - } - -// public void mapHateoasLinks() { -// -// } -} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java index 29f514b84..60adaecaf 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java @@ -18,20 +18,20 @@ package io.ballerina.openapi.service.mapper.model; +import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.SpecificFieldNode; -import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; -import io.ballerina.compiler.syntax.tree.Node; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; +// +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; /** * Visitor to get the ServiceDeclarationNode. @@ -39,7 +39,7 @@ */ public class ServiceNodeVisitor extends NodeVisitor { - public Map>> resourceMap = new HashMap<>(); +// public Map>> resourceMap = new HashMap<>(); // private String resourceName; // private String method; // private String operationId; @@ -51,7 +51,6 @@ public void visit(ServiceDeclarationNode serviceDeclarationNode) { child.accept(this); } } - System.out.println(resourceMap); } @Override From 5a4839096165f5cb96638111d0f96ceba8f15bc8 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 11:14:46 +0530 Subject: [PATCH 06/85] Implement hateoas meta-info sharing logic --- .../service/mapper/hateoas/ContextHolder.java | 57 +++++++++++++++++++ .../service/mapper/hateoas/Resource.java | 37 ++++++++++++ .../service/mapper/hateoas/Service.java | 49 ++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java new file mode 100644 index 000000000..36626369f --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.hateoas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public final class ContextHolder { + private static ContextHolder instance; + + private final List hateoasServices; + + private ContextHolder() { + this.hateoasServices = new ArrayList<>(); + } + + public static ContextHolder getHateoasContextHolder() { + synchronized (ContextHolder.class) { + if (Objects.isNull(instance)) { + instance = new ContextHolder(); + } + } + return instance; + } + + public Optional getHateoasResource(int serviceId, String resourceName, String resourceMethod) { + return this.hateoasServices.stream() + .filter(svc -> svc.getServiceId() == serviceId) + .findFirst() + .flatMap(svc -> svc.getHateoasResourceMapping().entrySet().stream() + .filter(resources -> resourceName.equals(resources.getKey())) + .findFirst() + ).flatMap(hateoasResourceMapping -> hateoasResourceMapping.getValue().stream() + .filter(resource -> resourceMethod.equals(resource.getResourceMethod())) + .findFirst() + ); + + } +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java new file mode 100644 index 000000000..dd9a7e659 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.hateoas; + +public class Resource { + private final String resourceMethod; + private final String operationId; + + public Resource(String resourceName, String resourceMethod, String operationId) { + this.resourceMethod = resourceMethod; + this.operationId = operationId; + } + + public String getResourceMethod() { + return resourceMethod; + } + + public String getOperationId() { + return operationId; + } +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java new file mode 100644 index 000000000..460e78324 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.hateoas; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Service { + private final int serviceId; + private final Map> hateoasResourceMapping = new HashMap<>(); + + public Service(int serviceId) { + this.serviceId = serviceId; + } + + public void addResource(String resourceName, Resource resource) { + if (hateoasResourceMapping.containsKey(resourceName)) { + hateoasResourceMapping.get(resourceName).add(resource); + return; + } + hateoasResourceMapping.put(resourceName, Arrays.asList(resource)); + } + + public int getServiceId() { + return serviceId; + } + + public Map> getHateoasResourceMapping() { + return hateoasResourceMapping; + } +} From e06bebbbb068501ff7fdb3fa64c111aa23bae80e Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 15:06:21 +0530 Subject: [PATCH 07/85] Remove unwanted node-visitor --- .../mapper/model/ServiceNodeVisitor.java | 102 ------------------ 1 file changed, 102 deletions(-) delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java deleted file mode 100644 index 60adaecaf..000000000 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceNodeVisitor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.ballerina.openapi.service.mapper.model; - -import io.ballerina.compiler.syntax.tree.AnnotationNode; -import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; -import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeVisitor; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.compiler.syntax.tree.SpecificFieldNode; -import io.ballerina.compiler.syntax.tree.SyntaxKind; -// -//import java.util.HashMap; -//import java.util.List; -//import java.util.Map; - -/** - * Visitor to get the ServiceDeclarationNode. - * - */ -public class ServiceNodeVisitor extends NodeVisitor { - -// public Map>> resourceMap = new HashMap<>(); -// private String resourceName; -// private String method; -// private String operationId; - - @Override - public void visit(ServiceDeclarationNode serviceDeclarationNode) { - for (Node child : serviceDeclarationNode.children()) { - if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { - child.accept(this); - } - } - } - - @Override - public void visit(FunctionDefinitionNode functionDefinitionNode) { - for (Node child : functionDefinitionNode.children()) { - if (SyntaxKind.METADATA.equals(child.kind())) { - child.accept(this); - } - } - } - - @Override - public void visit(MetadataNode metadataNode) { - metadataNode.children().get(0).accept(this); - } - - @Override - public void visit(AnnotationNode annotationNode) { - for (Node child : annotationNode.children()) { - if (SyntaxKind.MAPPING_CONSTRUCTOR.equals(child.kind())) { - child.accept(this); - } - } - } - - @Override - public void visit(MappingConstructorExpressionNode mappingConstructorExpressionNode) { - for (Node child : mappingConstructorExpressionNode.children()) { - if (SyntaxKind.SPECIFIC_FIELD.equals(child.kind())) { - child.accept(this); - } - } - } - - @Override - public void visit(SpecificFieldNode specificFieldNode) { - if (SyntaxKind.STRING_LITERAL.equals(specificFieldNode.children().get(2).kind())) { -// resourceName = specificFieldNode.children().get(2).toString().replace("\"",""); - } else { - specificFieldNode.children().get(2).accept(this); - } - } - - @Override - public void visit(ListConstructorExpressionNode listConstructorExpressionNode) { -// resourceLink = listConstructorExpressionNode.children().get(1); -// resourceMap.put(resourceName, resourceLink); - } -} From 7f0688f58b12ea6d36fdbf02d79ae06efce673ac Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 15:06:57 +0530 Subject: [PATCH 08/85] Update node-visiting logic to extract hateoas-metadata --- .../hateoas/HateoasMetadataVisitor.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java new file mode 100644 index 000000000..c529be1a1 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.hateoas; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; +import io.ballerina.compiler.api.symbols.Symbol; +import io.ballerina.compiler.syntax.tree.AnnotationNode; +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.Node; +import io.ballerina.compiler.syntax.tree.NodeList; +import io.ballerina.compiler.syntax.tree.NodeVisitor; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.ballerina.compiler.syntax.tree.SpecificFieldNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; + +import java.util.Optional; + +import static io.ballerina.openapi.service.mapper.hateoas.ContextHolder.getHateoasContextHolder; + +public class HateoasMetadataVisitor extends NodeVisitor { + private final SemanticModel semanticModel; + + public HateoasMetadataVisitor(SemanticModel semanticModel) { + this.semanticModel = semanticModel; + } + + @Override + public void visit(ServiceDeclarationNode serviceNode) { + boolean isHttpService = MapperCommonUtils.isHttpService(serviceNode, semanticModel); + if (!isHttpService) { + return; + } + Optional serviceDeclarationOpt = semanticModel.symbol(serviceNode); + if (serviceDeclarationOpt.isEmpty()) { + return; + } + ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); + int serviceId = serviceSymbol.hashCode(); + for (Node child : serviceNode.children()) { + if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { + FunctionDefinitionNode resourceFunction = (FunctionDefinitionNode) child; + String resourceMethod = resourceFunction.functionName().text(); + String operationId = generateOperationId(resourceFunction); + Optional resourceName = getResourceConfigAnnotation(resourceFunction) + .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "name")); + if (resourceName.isEmpty()) { + return; + } + Resource hateoasResource = new Resource(resourceMethod, operationId); + getHateoasContextHolder().updateHateoasResource(serviceId, resourceName.get(), hateoasResource); + } + } + } + + private String generateOperationId(FunctionDefinitionNode resourceFunction) { + String relativePath = MapperCommonUtils.generateRelativePath(resourceFunction); + String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); + String resName = (resourceFunction.functionName().text() + "_" + + cleanResourcePath).replaceAll("\\{///\\}", "_"); + + if (cleanResourcePath.equals("/")) { + resName = resourceFunction.functionName().text(); + } + return MapperCommonUtils.getOperationId(resName); + } + + private Optional getResourceConfigAnnotation(FunctionDefinitionNode resourceFunction) { + Optional metadata = resourceFunction.metadata(); + if (metadata.isEmpty()) { + return Optional.empty(); + } + MetadataNode metaData = metadata.get(); + NodeList annotations = metaData.annotations(); + return annotations.stream() + .filter(ann -> "http:ResourceConfig".equals(ann.annotReference().toString().trim())) + .findFirst(); + } + + private Optional getValueForAnnotationFields(AnnotationNode resourceConfigAnnotation, String fieldName) { + return resourceConfigAnnotation + .annotValue() + .map(MappingConstructorExpressionNode::fields) + .flatMap(fields -> + fields.stream() + .filter(fld -> fld instanceof SpecificFieldNode) + .map(fld -> (SpecificFieldNode) fld) + .filter(fld -> fieldName.equals(fld.fieldName().toString().trim())) + .findFirst() + ).flatMap(SpecificFieldNode::valueExpr) + .map(en -> en.toString().trim()); + } +} From 80cb40628135728fd0619e6449e0e3d86f1b7b1a Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 15:07:46 +0530 Subject: [PATCH 09/85] Update shared hateoas metadata updating logic --- .../service/mapper/hateoas/ContextHolder.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java index 36626369f..7b026d4f6 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java @@ -41,6 +41,20 @@ public static ContextHolder getHateoasContextHolder() { return instance; } + public void updateHateoasResource(int serviceId, String resourceName, Resource resource) { + Optional hateoasService = this.hateoasServices.stream() + .filter(svc -> svc.getServiceId() == serviceId) + .findFirst(); + if (hateoasService.isEmpty()) { + Service service = new Service(serviceId); + service.addResource(resourceName, resource); + this.hateoasServices.add(service); + return; + } + Service service = hateoasService.get(); + service.addResource(resourceName, resource); + } + public Optional getHateoasResource(int serviceId, String resourceName, String resourceMethod) { return this.hateoasServices.stream() .filter(svc -> svc.getServiceId() == serviceId) @@ -49,7 +63,7 @@ public Optional getHateoasResource(int serviceId, String resourceName, .filter(resources -> resourceName.equals(resources.getKey())) .findFirst() ).flatMap(hateoasResourceMapping -> hateoasResourceMapping.getValue().stream() - .filter(resource -> resourceMethod.equals(resource.getResourceMethod())) + .filter(resource -> resourceMethod.equals(resource.resourceMethod())) .findFirst() ); From 95b4d66c13392fee8aca8a23b05938ad82560594 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 15:08:11 +0530 Subject: [PATCH 10/85] Mark hateoas resource as a record --- .../service/mapper/hateoas/Resource.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index dd9a7e659..18c237a37 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -18,20 +18,5 @@ package io.ballerina.openapi.service.mapper.hateoas; -public class Resource { - private final String resourceMethod; - private final String operationId; - - public Resource(String resourceName, String resourceMethod, String operationId) { - this.resourceMethod = resourceMethod; - this.operationId = operationId; - } - - public String getResourceMethod() { - return resourceMethod; - } - - public String getOperationId() { - return operationId; - } +public record Resource(String resourceMethod, String operationId) { } From f3a2fb5f11eaf6d27f2632d9a54705ffa6e9af3c Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 15:08:42 +0530 Subject: [PATCH 11/85] Refactor common utility functions and their usage --- .../service/mapper/OpenAPIResourceMapper.java | 31 +++----------- .../mapper/utils/MapperCommonUtils.java | 40 ++++++++++--------- 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index 23ac06686..461ca4096 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -101,7 +101,8 @@ public void addMapping() { * @param httpMethods Sibling methods related to operation. */ private void getResourcePath(FunctionDefinitionNode resource, List httpMethods) { - String path = MapperCommonUtils.unescapeIdentifier(generateRelativePath(resource)); + String relativePath = MapperCommonUtils.generateRelativePath(resource); + String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); Operation operation; for (String httpMethod : httpMethods) { //Iterate through http methods and fill path map. @@ -113,10 +114,10 @@ private void getResourcePath(FunctionDefinitionNode resource, List httpM errors.add(error); } else { Optional operationAdaptor = convertResourceToOperation(resource, httpMethod, - path); + cleanResourcePath); if (operationAdaptor.isPresent()) { operation = operationAdaptor.get().getOperation(); - generatePathItem(httpMethod, pathObject, operation, path); + generatePathItem(httpMethod, pathObject, operation, cleanResourcePath); } else { break; } @@ -281,13 +282,13 @@ private List getHttpMethods(FunctionDefinitionNode resource) { ServiceDeclarationNode parentNode = (ServiceDeclarationNode) resource.parent(); NodeList siblings = parentNode.members(); httpMethods.add(resource.functionName().text()); - String relativePath = generateRelativePath(resource); + String relativePath = MapperCommonUtils.generateRelativePath(resource); for (Node function: siblings) { SyntaxKind kind = function.kind(); if (kind.equals(SyntaxKind.RESOURCE_ACCESSOR_DEFINITION)) { FunctionDefinitionNode sibling = (FunctionDefinitionNode) function; //need to build relative path - String siblingRelativePath = generateRelativePath(sibling); + String siblingRelativePath = MapperCommonUtils.generateRelativePath(sibling); if (relativePath.equals(siblingRelativePath)) { httpMethods.add(sibling.functionName().text()); } @@ -295,24 +296,4 @@ private List getHttpMethods(FunctionDefinitionNode resource) { } return new ArrayList<>(httpMethods); } - - private String generateRelativePath(FunctionDefinitionNode resource) { - - StringBuilder relativePath = new StringBuilder(); - relativePath.append("/"); - if (!resource.relativeResourcePath().isEmpty()) { - for (Node node: resource.relativeResourcePath()) { - if (node instanceof ResourcePathParameterNode pathNode) { - relativePath.append("{"); - relativePath.append(pathNode.paramName().get()); - relativePath.append("}"); - } else if ((resource.relativeResourcePath().size() == 1) && (node.toString().trim().equals("."))) { - return relativePath.toString(); - } else { - relativePath.append(node.toString().trim()); - } - } - } - return relativePath.toString(); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java index 70214075c..e76649589 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java @@ -34,25 +34,7 @@ import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; -import io.ballerina.compiler.syntax.tree.AbstractNodeFactory; -import io.ballerina.compiler.syntax.tree.AnnotationNode; -import io.ballerina.compiler.syntax.tree.BasicLiteralNode; -import io.ballerina.compiler.syntax.tree.ExpressionNode; -import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MappingFieldNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; -import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeList; -import io.ballerina.compiler.syntax.tree.NonTerminalNode; -import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode; -import io.ballerina.compiler.syntax.tree.RequiredParameterNode; -import io.ballerina.compiler.syntax.tree.SeparatedNodeList; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; -import io.ballerina.compiler.syntax.tree.SpecificFieldNode; -import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.compiler.syntax.tree.*; import io.ballerina.openapi.service.mapper.Constants; import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.ExceptionDiagnostic; @@ -220,6 +202,26 @@ public static Schema getOpenApiSchema(SyntaxKind type) { return schema; } + public static String generateRelativePath(FunctionDefinitionNode resourceFunction) { + StringBuilder relativePath = new StringBuilder(); + relativePath.append("/"); + if (!resourceFunction.relativeResourcePath().isEmpty()) { + for (Node node: resourceFunction.relativeResourcePath()) { + if (node instanceof ResourcePathParameterNode pathNode) { + relativePath.append("{"); + relativePath.append(pathNode.paramName().get()); + relativePath.append("}"); + } else if ((resourceFunction.relativeResourcePath().size() == 1) + && (node.toString().trim().equals("."))) { + return relativePath.toString(); + } else { + relativePath.append(node.toString().trim()); + } + } + } + return relativePath.toString(); + } + /** * Generate operationId by removing special characters. * From 527b921b629ac53cb1c21996e57f3b2ace98ceee Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Thu, 4 Jan 2024 15:23:08 +0530 Subject: [PATCH 12/85] Fix checkstyle violations --- .../service/mapper/OpenAPIResourceMapper.java | 1 - .../mapper/utils/MapperCommonUtils.java | 21 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index 461ca4096..a83c7bf5f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -26,7 +26,6 @@ import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeList; -import io.ballerina.compiler.syntax.tree.ResourcePathParameterNode; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java index e76649589..bea027c6d 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java @@ -34,7 +34,26 @@ import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; -import io.ballerina.compiler.syntax.tree.*; +import io.ballerina.compiler.syntax.tree.AbstractNodeFactory; +import io.ballerina.compiler.syntax.tree.AnnotationNode; +import io.ballerina.compiler.syntax.tree.BasicLiteralNode; +import io.ballerina.compiler.syntax.tree.ExpressionNode; +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MappingFieldNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.Node; +import io.ballerina.compiler.syntax.tree.NodeList; +import io.ballerina.compiler.syntax.tree.NonTerminalNode; +import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode; +import io.ballerina.compiler.syntax.tree.RequiredParameterNode; +import io.ballerina.compiler.syntax.tree.ResourcePathParameterNode; +import io.ballerina.compiler.syntax.tree.SeparatedNodeList; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; +import io.ballerina.compiler.syntax.tree.SpecificFieldNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.openapi.service.mapper.Constants; import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.ExceptionDiagnostic; From 96d2951c07a369bb10336c4ab4bc7c4c52b7b1fa Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Thu, 4 Jan 2024 16:46:28 +0530 Subject: [PATCH 13/85] Add hateoas mapper --- .../mapper/parameter/HateoasMapper.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java new file mode 100644 index 000000000..16b4ba119 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.parameter; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; +import io.ballerina.compiler.api.symbols.Symbol; +import io.ballerina.compiler.syntax.tree.*; +import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; + +import java.util.List; +import java.util.Optional; + +public class HateoasMapper { + private int serviceId; + public HateoasMapper(int serviceId) { + this.serviceId = serviceId; + } + + private int getServiceId(SemanticModel semanticModel, ServiceDeclarationNode serviceNode) { + Optional serviceDeclarationOpt = semanticModel.symbol(serviceNode); + ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); + serviceId = serviceSymbol.hashCode(); + return serviceId; + } + + public void mapHateoasLink(int serviceId, FunctionDefinitionNode resourceFunction) { + Optional linkedTo = getResourceConfigAnnotation(resourceFunction) + .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); + if (linkedTo.isEmpty()) { + return; + } + List links = getLinks(linkedTo.get()); + } + + // todo: implement this properly + private List getLinks(String linkedTo) { + return List.of(); + } + + private Optional getResourceConfigAnnotation(FunctionDefinitionNode resourceFunction) { + Optional metadata = resourceFunction.metadata(); + if (metadata.isEmpty()) { + return Optional.empty(); + } + MetadataNode metaData = metadata.get(); + NodeList annotations = metaData.annotations(); + return annotations.stream() + .filter(ann -> "http:ResourceConfig".equals(ann.annotReference().toString().trim())) + .findFirst(); + } + + private Optional getValueForAnnotationFields(AnnotationNode resourceConfigAnnotation, String fieldName) { + return resourceConfigAnnotation + .annotValue() + .map(MappingConstructorExpressionNode::fields) + .flatMap(fields -> + fields.stream() + .filter(fld -> fld instanceof SpecificFieldNode) + .map(fld -> (SpecificFieldNode) fld) + .filter(fld -> fieldName.equals(fld.fieldName().toString().trim())) + .findFirst() + ).flatMap(SpecificFieldNode::valueExpr) + .map(en -> en.toString().trim()); + } +} From fbedc3745942a95a91e505b44a6c2735df7b4855 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Thu, 4 Jan 2024 16:49:44 +0530 Subject: [PATCH 14/85] Implementing hateoas link object --- .../mapper/parameter/model/HateoasLink.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java new file mode 100644 index 000000000..d1805d358 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.parameter.model; + +public class HateoasLink { + private String resourceName; + private String rel; + private String resourceMethod; + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getRel() { + return rel; + } + + public void setRel(String rel) { + this.rel = rel; + } + + public String getResourceMethod() { + return resourceMethod; + } + + public void setResourceMethod(String resourceMethod) { + this.resourceMethod = resourceMethod; + } +} From a3a826dc3cf22772ee190ba63878a6c7ee6b8afd Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Thu, 4 Jan 2024 17:20:47 +0530 Subject: [PATCH 15/85] Fix checkstyle violations --- .../openapi/service/mapper/parameter/HateoasMapper.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 16b4ba119..4993b419f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -21,7 +21,13 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; -import io.ballerina.compiler.syntax.tree.*; +import io.ballerina.compiler.syntax.tree.AnnotationNode; +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.ballerina.compiler.syntax.tree.SpecificFieldNode; +import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; import java.util.List; From 4dca3fe789fe566a09eff841d79f3c33e319a3f5 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 5 Jan 2024 11:12:44 +0530 Subject: [PATCH 16/85] Improve hateoas mapper --- .../service/mapper/hateoas/ContextHolder.java | 3 +- .../mapper/parameter/HateoasMapper.java | 73 ++++++++++++++----- .../mapper/parameter/ResponseMapper.java | 15 ++-- 3 files changed, 64 insertions(+), 27 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java index 7b026d4f6..569e888ab 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java @@ -28,7 +28,7 @@ public final class ContextHolder { private final List hateoasServices; - private ContextHolder() { + public ContextHolder() { this.hateoasServices = new ArrayList<>(); } @@ -66,6 +66,5 @@ public Optional getHateoasResource(int serviceId, String resourceName, .filter(resource -> resourceMethod.equals(resource.resourceMethod())) .findFirst() ); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 4993b419f..abe0f5096 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -18,46 +18,79 @@ package io.ballerina.openapi.service.mapper.parameter; -import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; -import io.ballerina.compiler.api.symbols.Symbol; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Optional; +import java.util.HashMap; + +import io.swagger.v3.oas.models.links.Link; +import io.swagger.v3.oas.models.responses.ApiResponse; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.MetadataNode; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.compiler.syntax.tree.SpecificFieldNode; import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; import io.ballerina.compiler.syntax.tree.NodeList; +import io.ballerina.openapi.service.mapper.hateoas.ContextHolder; +import io.ballerina.openapi.service.mapper.hateoas.Resource; import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; -import java.util.List; -import java.util.Optional; - public class HateoasMapper { - private int serviceId; - public HateoasMapper(int serviceId) { - this.serviceId = serviceId; - } + Map hateoasLinks; + public HateoasMapper() { - private int getServiceId(SemanticModel semanticModel, ServiceDeclarationNode serviceNode) { - Optional serviceDeclarationOpt = semanticModel.symbol(serviceNode); - ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); - serviceId = serviceSymbol.hashCode(); - return serviceId; } - public void mapHateoasLink(int serviceId, FunctionDefinitionNode resourceFunction) { + public Map mapHateoasLinks(int serviceId, FunctionDefinitionNode resourceFunction, + ApiResponse apiResponse) { Optional linkedTo = getResourceConfigAnnotation(resourceFunction) .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); if (linkedTo.isEmpty()) { - return; + return Collections.emptyMap(); } List links = getLinks(linkedTo.get()); + ContextHolder contextHolder = new ContextHolder(); + Link swaggerLink = new Link(); + for (HateoasLink link : links) { + Optional resource = contextHolder.getHateoasResource(serviceId, link.getResourceName(), + link.getResourceMethod()); + if (resource.isPresent()) { + String operationId = resource.get().operationId(); + swaggerLink.setOperationId(operationId); + hateoasLinks.put(link.getRel(), swaggerLink); + } + } + return hateoasLinks; } - // todo: implement this properly private List getLinks(String linkedTo) { - return List.of(); + List links = new ArrayList<>(); + String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split(",\\s*"); + for (String linkString : linkArray) { + HateoasLink link = parseHateoasLink(linkString); + links.add(link); + } + return links; + } + + public static HateoasLink parseHateoasLink(String input) { + HateoasLink hateoasLink = new HateoasLink(); + HashMap keyValueMap = new HashMap<>(); + String[] keyValuePairs = input.replaceAll("[{}]", "").split(",\\s*"); + for (String pair : keyValuePairs) { + String[] parts = pair.split(":\\s*"); + if (parts.length == 2) { + String key = parts[0].trim(); + String value = parts[1].replaceAll("\"", "").trim(); + keyValueMap.put(key, value); + } + } + hateoasLink.setResourceName(keyValueMap.get("name")); + hateoasLink.setRel(keyValueMap.get("rel")); + hateoasLink.setResourceMethod(keyValueMap.get("method")); + return hateoasLink; } private Optional getResourceConfigAnnotation(FunctionDefinitionNode resourceFunction) { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java index f19375151..41a48c085 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java @@ -28,11 +28,13 @@ import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; +import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.openapi.service.mapper.AdditionalData; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; @@ -210,10 +212,13 @@ private void addResponseContent(TypeSymbol returnType, ApiResponse apiResponse, } } -// private void addResponseLinks(ApiResponse apiResponse, ServiceNodeVisitor serviceNodeVisitor) { -// HateoasMapper hateoasMapper = new HateoasMapper(semanticModel, serviceNodeVisitor); -// apiResponse.setLinks(serviceNodeVisitor.resourceMap); -// } + private void addResponseLinks(ApiResponse apiResponse, ServiceDeclarationNode serviceNode) { + Optional serviceDeclarationOpt = semanticModel.symbol(serviceNode); + ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); + int serviceId = serviceSymbol.hashCode(); + HateoasMapper hateoasMapper = new HateoasMapper(); +// apiResponse.setLinks(); + } public void addApiResponse(ApiResponse apiResponse, String statusCode) { addHeaders(apiResponse, statusCode); @@ -292,7 +297,7 @@ private void addResponseMappingForHttpResponse() { ApiResponse apiResponse = new ApiResponse(); apiResponse.setDescription("Any Response"); apiResponse.setContent(new Content().addMediaType("*/*", mediaTypeObj)); -// addResponseLinks(apiResponse, new ServiceNodeVisitor()); +// addResponseLinks(apiResponse,); addApiResponse(apiResponse, "default"); } From 82c3cd7a993080763f5ee705147f83475ef55945 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 13:52:17 +0530 Subject: [PATCH 17/85] Refactor HateoasLink to SwaggerLink mapping-logic --- .../openapi/service/mapper/parameter/HateoasMapper.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index abe0f5096..935354dd0 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -38,10 +38,6 @@ import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; public class HateoasMapper { - Map hateoasLinks; - public HateoasMapper() { - - } public Map mapHateoasLinks(int serviceId, FunctionDefinitionNode resourceFunction, ApiResponse apiResponse) { @@ -52,11 +48,12 @@ public Map mapHateoasLinks(int serviceId, FunctionDefinitionNode r } List links = getLinks(linkedTo.get()); ContextHolder contextHolder = new ContextHolder(); - Link swaggerLink = new Link(); + Map hateoasLinks = new HashMap<>(); for (HateoasLink link : links) { Optional resource = contextHolder.getHateoasResource(serviceId, link.getResourceName(), link.getResourceMethod()); if (resource.isPresent()) { + Link swaggerLink = new Link(); String operationId = resource.get().operationId(); swaggerLink.setOperationId(operationId); hateoasLinks.put(link.getRel(), swaggerLink); From 4dfc46793fc5b3bb20f1613e77bc7d5e9d50c2d8 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 13:56:46 +0530 Subject: [PATCH 18/85] Refactor method name --- .../openapi/service/mapper/parameter/HateoasMapper.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 935354dd0..c4d83612a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -26,7 +26,6 @@ import java.util.HashMap; import io.swagger.v3.oas.models.links.Link; -import io.swagger.v3.oas.models.responses.ApiResponse; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.MetadataNode; @@ -39,8 +38,8 @@ public class HateoasMapper { - public Map mapHateoasLinks(int serviceId, FunctionDefinitionNode resourceFunction, - ApiResponse apiResponse) { + public Map mapHateoasLinksToSwaggerLinks(int serviceId, + FunctionDefinitionNode resourceFunction) { Optional linkedTo = getResourceConfigAnnotation(resourceFunction) .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); if (linkedTo.isEmpty()) { From 4b57fec7ef88857dacd4881c2a5da3a5872de045 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 5 Jan 2024 15:41:01 +0530 Subject: [PATCH 19/85] Resolve merge conflicts in response mapper --- .../service/mapper/parameter/ResponseMapper.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java index 41a48c085..ddb9645f1 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java @@ -28,13 +28,11 @@ import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; -import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.openapi.service.mapper.AdditionalData; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; @@ -212,14 +210,6 @@ private void addResponseContent(TypeSymbol returnType, ApiResponse apiResponse, } } - private void addResponseLinks(ApiResponse apiResponse, ServiceDeclarationNode serviceNode) { - Optional serviceDeclarationOpt = semanticModel.symbol(serviceNode); - ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); - int serviceId = serviceSymbol.hashCode(); - HateoasMapper hateoasMapper = new HateoasMapper(); -// apiResponse.setLinks(); - } - public void addApiResponse(ApiResponse apiResponse, String statusCode) { addHeaders(apiResponse, statusCode); if (apiResponses.containsKey(statusCode)) { @@ -297,7 +287,6 @@ private void addResponseMappingForHttpResponse() { ApiResponse apiResponse = new ApiResponse(); apiResponse.setDescription("Any Response"); apiResponse.setContent(new Content().addMediaType("*/*", mediaTypeObj)); -// addResponseLinks(apiResponse,); addApiResponse(apiResponse, "default"); } From affe803e5c58de56aad3244462c8920c2e3074ab Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 16:44:53 +0530 Subject: [PATCH 20/85] Refactor common utilities --- .../hateoas/HateoasMetadataVisitor.java | 34 ++----------------- .../mapper/parameter/HateoasMapper.java | 34 ++----------------- .../mapper/utils/MapperCommonUtils.java | 27 +++++++++++++++ 3 files changed, 32 insertions(+), 63 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index c529be1a1..bd1e0a9df 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -21,21 +21,18 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; -import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.compiler.syntax.tree.SpecificFieldNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; import java.util.Optional; import static io.ballerina.openapi.service.mapper.hateoas.ContextHolder.getHateoasContextHolder; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; public class HateoasMetadataVisitor extends NodeVisitor { private final SemanticModel semanticModel; @@ -77,36 +74,9 @@ private String generateOperationId(FunctionDefinitionNode resourceFunction) { String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); String resName = (resourceFunction.functionName().text() + "_" + cleanResourcePath).replaceAll("\\{///\\}", "_"); - if (cleanResourcePath.equals("/")) { resName = resourceFunction.functionName().text(); } return MapperCommonUtils.getOperationId(resName); } - - private Optional getResourceConfigAnnotation(FunctionDefinitionNode resourceFunction) { - Optional metadata = resourceFunction.metadata(); - if (metadata.isEmpty()) { - return Optional.empty(); - } - MetadataNode metaData = metadata.get(); - NodeList annotations = metaData.annotations(); - return annotations.stream() - .filter(ann -> "http:ResourceConfig".equals(ann.annotReference().toString().trim())) - .findFirst(); - } - - private Optional getValueForAnnotationFields(AnnotationNode resourceConfigAnnotation, String fieldName) { - return resourceConfigAnnotation - .annotValue() - .map(MappingConstructorExpressionNode::fields) - .flatMap(fields -> - fields.stream() - .filter(fld -> fld instanceof SpecificFieldNode) - .map(fld -> (SpecificFieldNode) fld) - .filter(fld -> fieldName.equals(fld.fieldName().toString().trim())) - .findFirst() - ).flatMap(SpecificFieldNode::valueExpr) - .map(en -> en.toString().trim()); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index c4d83612a..691d780e6 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -26,16 +26,14 @@ import java.util.HashMap; import io.swagger.v3.oas.models.links.Link; -import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; -import io.ballerina.compiler.syntax.tree.SpecificFieldNode; -import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; -import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.openapi.service.mapper.hateoas.ContextHolder; import io.ballerina.openapi.service.mapper.hateoas.Resource; import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; + public class HateoasMapper { public Map mapHateoasLinksToSwaggerLinks(int serviceId, @@ -88,30 +86,4 @@ public static HateoasLink parseHateoasLink(String input) { hateoasLink.setResourceMethod(keyValueMap.get("method")); return hateoasLink; } - - private Optional getResourceConfigAnnotation(FunctionDefinitionNode resourceFunction) { - Optional metadata = resourceFunction.metadata(); - if (metadata.isEmpty()) { - return Optional.empty(); - } - MetadataNode metaData = metadata.get(); - NodeList annotations = metaData.annotations(); - return annotations.stream() - .filter(ann -> "http:ResourceConfig".equals(ann.annotReference().toString().trim())) - .findFirst(); - } - - private Optional getValueForAnnotationFields(AnnotationNode resourceConfigAnnotation, String fieldName) { - return resourceConfigAnnotation - .annotValue() - .map(MappingConstructorExpressionNode::fields) - .flatMap(fields -> - fields.stream() - .filter(fld -> fld instanceof SpecificFieldNode) - .map(fld -> (SpecificFieldNode) fld) - .filter(fld -> fieldName.equals(fld.fieldName().toString().trim())) - .findFirst() - ).flatMap(SpecificFieldNode::valueExpr) - .map(en -> en.toString().trim()); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java index bea027c6d..c7119a55e 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java @@ -641,4 +641,31 @@ public static Map getComponentsSchema(OpenAPI openAPI) { } return schemas; } + + public static Optional getResourceConfigAnnotation(FunctionDefinitionNode resourceFunction) { + Optional metadata = resourceFunction.metadata(); + if (metadata.isEmpty()) { + return Optional.empty(); + } + MetadataNode metaData = metadata.get(); + NodeList annotations = metaData.annotations(); + return annotations.stream() + .filter(ann -> "http:ResourceConfig".equals(ann.annotReference().toString().trim())) + .findFirst(); + } + + public static Optional getValueForAnnotationFields(AnnotationNode resourceConfigAnnotation, + String fieldName) { + return resourceConfigAnnotation + .annotValue() + .map(MappingConstructorExpressionNode::fields) + .flatMap(fields -> + fields.stream() + .filter(fld -> fld instanceof SpecificFieldNode) + .map(fld -> (SpecificFieldNode) fld) + .filter(fld -> fieldName.equals(fld.fieldName().toString().trim())) + .findFirst() + ).flatMap(SpecificFieldNode::valueExpr) + .map(en -> en.toString().trim()); + } } From 2594e9906dee0c6845187d5d361d06b2dabdd0fc Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 16:50:07 +0530 Subject: [PATCH 21/85] Add logic to incorporate hateoas-metadata visitor execution --- .../service/mapper/ServiceToOpenAPIMapper.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 7bea627e2..b3b799fb8 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -40,6 +40,7 @@ import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.ExceptionDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; +import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; @@ -203,6 +204,7 @@ private static void extractServiceNodes(String serviceName, List availab public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) { ServiceDeclarationNode serviceDefinition = oasGenerationMetaInfo.getServiceDeclarationNode(); ModuleMemberVisitor moduleMemberVisitor = extractNodesFromProject(oasGenerationMetaInfo.getProject()); + extractHateoasLinkMetadata(oasGenerationMetaInfo.getProject()); Set listeners = moduleMemberVisitor.getListenerDeclarationNodes(); SemanticModel semanticModel = oasGenerationMetaInfo.getSemanticModel(); String openApiFileName = oasGenerationMetaInfo.getOpenApiFileName(); @@ -501,4 +503,16 @@ public static ModuleMemberVisitor extractNodesFromProject(Project project) { }); return balNodeVisitor; } + + public static void extractHateoasLinkMetadata(Project project) { + project.currentPackage().moduleIds().forEach(moduleId -> { + Module module = project.currentPackage().module(moduleId); + SemanticModel semanticModel = project.currentPackage().getCompilation().getSemanticModel(moduleId); + HateoasMetadataVisitor hateoasMetadataVisitor = new HateoasMetadataVisitor(semanticModel); + module.documentIds().forEach(documentId -> { + SyntaxTree syntaxTreeDoc = module.document(documentId).syntaxTree(); + syntaxTreeDoc.rootNode().accept(hateoasMetadataVisitor); + }); + }); + } } From 36358f3ff575f042f5197857a76fd8df050eacd9 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 5 Jan 2024 17:13:53 +0530 Subject: [PATCH 22/85] Add links to Api response --- .../service/mapper/OpenAPIResourceMapper.java | 28 +++++++++++++++---- .../service/mapper/OpenAPIServiceMapper.java | 2 +- .../mapper/parameter/HateoasMapper.java | 4 +-- .../mapper/parameter/model/HateoasLink.java | 8 +++--- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index a83c7bf5f..192732388 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -22,6 +22,7 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.Documentable; import io.ballerina.compiler.api.symbols.Documentation; +import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.Node; @@ -33,6 +34,7 @@ import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OperationAdaptor; +import io.ballerina.openapi.service.mapper.parameter.HateoasMapper; import io.ballerina.openapi.service.mapper.parameter.ResponseMapper; import io.ballerina.openapi.service.mapper.type.TypeMapper; import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; @@ -42,6 +44,8 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.links.Link; +import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; import java.util.ArrayList; @@ -70,6 +74,7 @@ public class OpenAPIResourceMapper { private final TypeMapper typeMapper; private final OpenAPI openAPI; private final List resources; + private final HateoasMapper hateoasMapper; /** * Initializes a resource parser for openApi. @@ -83,12 +88,13 @@ public class OpenAPIResourceMapper { this.errors = errors; this.moduleMemberVisitor = moduleMemberVisitor; this.typeMapper = typeMapper; + this.hateoasMapper = new HateoasMapper(); } - public void addMapping() { + public void addMapping(ServiceDeclarationNode service) { for (FunctionDefinitionNode resource : resources) { List methods = this.getHttpMethods(resource); - getResourcePath(resource, methods); + getResourcePath(resource, methods, service); } openAPI.setPaths(pathObject); } @@ -99,7 +105,7 @@ public void addMapping() { * @param resource The ballerina resource. * @param httpMethods Sibling methods related to operation. */ - private void getResourcePath(FunctionDefinitionNode resource, List httpMethods) { + private void getResourcePath(FunctionDefinitionNode resource, List httpMethods, ServiceDeclarationNode service) { String relativePath = MapperCommonUtils.generateRelativePath(resource); String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); Operation operation; @@ -113,7 +119,7 @@ private void getResourcePath(FunctionDefinitionNode resource, List httpM errors.add(error); } else { Optional operationAdaptor = convertResourceToOperation(resource, httpMethod, - cleanResourcePath); + cleanResourcePath, service); if (operationAdaptor.isPresent()) { operation = operationAdaptor.get().getOperation(); generatePathItem(httpMethod, pathObject, operation, cleanResourcePath); @@ -195,7 +201,8 @@ private void generatePathItem(String httpMethod, Paths path, Operation operation * @return Operation Adaptor object of given resource */ private Optional convertResourceToOperation(FunctionDefinitionNode resource, String httpMethod, - String generateRelativePath) { + String generateRelativePath, + ServiceDeclarationNode service) { OperationAdaptor op = new OperationAdaptor(); op.setHttpOperation(httpMethod); op.setPath(generateRelativePath); @@ -231,6 +238,17 @@ private Optional convertResourceToOperation(FunctionDefinition ResponseMapper responseMapper = new ResponseMapper(semanticModel, openAPI, resource, op, errors, moduleMemberVisitor); ApiResponses apiResponses = responseMapper.getApiResponses(); + Optional serviceDeclarationOpt = semanticModel.symbol(service); + ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); + int serviceId = serviceSymbol.hashCode(); + Map swaggerLinks = this.hateoasMapper.mapHateoasLinksToSwaggerLinks(serviceId, resource); + for (Map.Entry entry : apiResponses.entrySet()) { + int statusCode = Integer.parseInt(entry.getKey()); + if (statusCode >= 200 && statusCode < 300) { + entry.getValue().getLinks().putAll(swaggerLinks); + System.out.println("chipi chipi chapa chapa"); + } + } op.getOperation().setResponses(apiResponses); return Optional.of(op); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java index 0540d60c7..fdf99fe0d 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java @@ -77,7 +77,7 @@ public OpenAPI convertServiceToOpenAPI(ServiceDeclarationNode service, OpenAPI o TypeMapper typeMapper = new TypeMapper(openapi, semanticModel, moduleMemberVisitor, errors); OpenAPIResourceMapper resourceMapper = new OpenAPIResourceMapper(openapi, resources, semanticModel, moduleMemberVisitor, errors, typeMapper); - resourceMapper.addMapping(); + resourceMapper.addMapping(service); ConstraintMapper constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, errors); constraintMapper.addMapping(); return openapi; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 691d780e6..c6c803404 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -61,7 +61,7 @@ public Map mapHateoasLinksToSwaggerLinks(int serviceId, private List getLinks(String linkedTo) { List links = new ArrayList<>(); - String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split(",\\s*"); + String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split("},\\\\s*"); for (String linkString : linkArray) { HateoasLink link = parseHateoasLink(linkString); links.add(link); @@ -82,7 +82,7 @@ public static HateoasLink parseHateoasLink(String input) { } } hateoasLink.setResourceName(keyValueMap.get("name")); - hateoasLink.setRel(keyValueMap.get("rel")); + hateoasLink.setRel(keyValueMap.get("relation")); hateoasLink.setResourceMethod(keyValueMap.get("method")); return hateoasLink; } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java index d1805d358..f5d114f30 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java @@ -20,7 +20,7 @@ public class HateoasLink { private String resourceName; - private String rel; + private String relation; private String resourceMethod; public String getResourceName() { @@ -32,11 +32,11 @@ public void setResourceName(String resourceName) { } public String getRel() { - return rel; + return relation; } - public void setRel(String rel) { - this.rel = rel; + public void setRel(String relation) { + this.relation = relation; } public String getResourceMethod() { From 01f814e3a74573b2cad7fb68e04a49090d3390c3 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 17:38:42 +0530 Subject: [PATCH 23/85] Fix checkstyle violations --- .../openapi/service/mapper/OpenAPIResourceMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index 192732388..988d943ce 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -105,7 +105,8 @@ public void addMapping(ServiceDeclarationNode service) { * @param resource The ballerina resource. * @param httpMethods Sibling methods related to operation. */ - private void getResourcePath(FunctionDefinitionNode resource, List httpMethods, ServiceDeclarationNode service) { + private void getResourcePath(FunctionDefinitionNode resource, List httpMethods, + ServiceDeclarationNode service) { String relativePath = MapperCommonUtils.generateRelativePath(resource); String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); Operation operation; @@ -246,7 +247,6 @@ private Optional convertResourceToOperation(FunctionDefinition int statusCode = Integer.parseInt(entry.getKey()); if (statusCode >= 200 && statusCode < 300) { entry.getValue().getLinks().putAll(swaggerLinks); - System.out.println("chipi chipi chapa chapa"); } } op.getOperation().setResponses(apiResponses); From 4a4ab1473ccb4033d76211c3f24002050301d761 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 17:39:08 +0530 Subject: [PATCH 24/85] Refactor shared-context usage logic --- .../mapper/parameter/HateoasMapper.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index c6c803404..dca8fb98f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -18,19 +18,19 @@ package io.ballerina.openapi.service.mapper.parameter; -import java.util.Map; -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Optional; -import java.util.HashMap; - -import io.swagger.v3.oas.models.links.Link; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.openapi.service.mapper.hateoas.ContextHolder; import io.ballerina.openapi.service.mapper.hateoas.Resource; import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; +import io.swagger.v3.oas.models.links.Link; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import static io.ballerina.openapi.service.mapper.hateoas.ContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; @@ -44,11 +44,10 @@ public Map mapHateoasLinksToSwaggerLinks(int serviceId, return Collections.emptyMap(); } List links = getLinks(linkedTo.get()); - ContextHolder contextHolder = new ContextHolder(); Map hateoasLinks = new HashMap<>(); for (HateoasLink link : links) { - Optional resource = contextHolder.getHateoasResource(serviceId, link.getResourceName(), - link.getResourceMethod()); + Optional resource = getHateoasContextHolder() + .getHateoasResource(serviceId, link.getResourceName(), link.getResourceMethod()); if (resource.isPresent()) { Link swaggerLink = new Link(); String operationId = resource.get().operationId(); From e00b24c8a27639ac6146c99413efd9fadd30c62f Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 18:01:04 +0530 Subject: [PATCH 25/85] Remove unwanted quotations from hateoas resource-name --- .../openapi/service/mapper/hateoas/HateoasMetadataVisitor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index bd1e0a9df..decec0921 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -63,8 +63,9 @@ public void visit(ServiceDeclarationNode serviceNode) { if (resourceName.isEmpty()) { return; } + String cleanedResourceName = resourceName.get().replaceAll("\"", ""); Resource hateoasResource = new Resource(resourceMethod, operationId); - getHateoasContextHolder().updateHateoasResource(serviceId, resourceName.get(), hateoasResource); + getHateoasContextHolder().updateHateoasResource(serviceId, cleanedResourceName, hateoasResource); } } } From 1294e6a6b388daa19a9bb92025bb80fb293d908c Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 5 Jan 2024 18:01:32 +0530 Subject: [PATCH 26/85] Fix swagger-links adding logic --- .../openapi/service/mapper/OpenAPIResourceMapper.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index 988d943ce..ffeef0dcd 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -243,10 +243,12 @@ private Optional convertResourceToOperation(FunctionDefinition ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); int serviceId = serviceSymbol.hashCode(); Map swaggerLinks = this.hateoasMapper.mapHateoasLinksToSwaggerLinks(serviceId, resource); - for (Map.Entry entry : apiResponses.entrySet()) { - int statusCode = Integer.parseInt(entry.getKey()); - if (statusCode >= 200 && statusCode < 300) { - entry.getValue().getLinks().putAll(swaggerLinks); + if (!swaggerLinks.isEmpty()) { + for (Map.Entry entry : apiResponses.entrySet()) { + int statusCode = Integer.parseInt(entry.getKey()); + if (statusCode >= 200 && statusCode < 300) { + entry.getValue().setLinks(swaggerLinks); + } } } op.getOperation().setResponses(apiResponses); From 466a545bb063a7217e264f36527005e748c7cce7 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 5 Jan 2024 18:09:10 +0530 Subject: [PATCH 27/85] Add swagger links to Api response --- .../ballerina/openapi/service/mapper/OpenAPIResourceMapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index ffeef0dcd..35463ecae 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -248,6 +248,8 @@ private Optional convertResourceToOperation(FunctionDefinition int statusCode = Integer.parseInt(entry.getKey()); if (statusCode >= 200 && statusCode < 300) { entry.getValue().setLinks(swaggerLinks); + ApiResponse apiResponse = new ApiResponse(); + apiResponse.setLinks(swaggerLinks); } } } From 08f04e3c375546a469d8f5c454d76c44d83b5d34 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Sun, 7 Jan 2024 23:28:38 +0530 Subject: [PATCH 28/85] Improve setting swagger links in Api response --- .../openapi/service/mapper/OpenAPIResourceMapper.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index 35463ecae..b74711f3f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -32,6 +32,7 @@ import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.IncompatibleResourceDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; +import io.ballerina.openapi.service.mapper.hateoas.Resource; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OperationAdaptor; import io.ballerina.openapi.service.mapper.parameter.HateoasMapper; @@ -239,6 +240,13 @@ private Optional convertResourceToOperation(FunctionDefinition ResponseMapper responseMapper = new ResponseMapper(semanticModel, openAPI, resource, op, errors, moduleMemberVisitor); ApiResponses apiResponses = responseMapper.getApiResponses(); + setSwaggerLinksInApiResponse(semanticModel, service, apiResponses, resource); + op.getOperation().setResponses(apiResponses); + return Optional.of(op); + } + + private void setSwaggerLinksInApiResponse(SemanticModel semanticModel, ServiceDeclarationNode service, ApiResponses apiResponses, + FunctionDefinitionNode resource) { Optional serviceDeclarationOpt = semanticModel.symbol(service); ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); int serviceId = serviceSymbol.hashCode(); @@ -253,8 +261,6 @@ private Optional convertResourceToOperation(FunctionDefinition } } } - op.getOperation().setResponses(apiResponses); - return Optional.of(op); } private boolean checkRestParamInResourcePath(OpenAPIParameterMapper openAPIParameterMapper) { From 0ff1631ef7f1c2ce24bd504db5d5a98391d81dfd Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Sun, 7 Jan 2024 23:31:53 +0530 Subject: [PATCH 29/85] Add tests --- .../generators/openapi/HateoasTests.java | 8 +- .../hateoas/hateoas_multiple_links.yaml | 113 ++++++++++++++++++ .../hateoas/hateoas_multiple_links.bal | 48 ++++++++ 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java index eaa7c5848..ae8c28c07 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -26,9 +26,15 @@ public class HateoasTests { private static final Path RES_DIR = Paths.get("src/test/resources/ballerina-to-openapi").toAbsolutePath(); - @Test(description = "Automatic linking between resoruce functions") + @Test(description = "Automatic linking between resource functions") public void testHateoasAutomaticLinking() throws IOException { Path ballerinafilePath = RES_DIR.resolve("hateoas/hateoas_automatic_linking.bal"); TestUtils.compareWithGeneratedFile(ballerinafilePath, "hateoas/hateoas_automatic_linking.yaml"); } + + @Test(description = "Multiple reference links to a resource") + public void testHateoasMultipleLinks() throws IOException { + Path ballerinafilePath = RES_DIR.resolve("hateoas/hateoas_multiple_links.bal"); + TestUtils.compareWithGeneratedFile(ballerinafilePath, "hateoas/hateoas_multiple_links.yaml"); + } } diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml new file mode 100644 index 000000000..a85dcfcb1 --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml @@ -0,0 +1,113 @@ +openapi: 3.0.1 +info: + title: PayloadV + version: 0.0.0 +servers: + - url: "{server}:{port}/payloadV" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /locations: + get: + operationId: getLocations + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/Location' + links: + room: + operationId: getLocationsIdRooms + payment: + operationId: getLocationsIdPayments + /locations/{id}/rooms: + get: + operationId: getLocationsIdRooms + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "202": + description: Accepted + "500": + description: InternalServerError + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + /locations/{id}/payments: + get: + operationId: getLocationsIdPayments + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "202": + description: Accepted + "500": + description: InternalServerError + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' +components: + schemas: + Location: + required: + - address + - id + - name + type: object + properties: + name: + type: string + id: + type: string + address: + type: string + ErrorPayload: + required: + - message + - method + - path + - reason + - status + - timestamp + type: object + properties: + timestamp: + type: string + status: + type: integer + format: int64 + reason: + type: string + message: + type: string + path: + type: string + method: + type: string diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal new file mode 100644 index 000000000..2becb1ece --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal @@ -0,0 +1,48 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +public type Location record { + string name; + string id; + string address; +}; + +service /payloadV on new http:Listener(9090) { + @http:ResourceConfig { + name: "Locations", + linkedTo: [ {name: "Rooms", relation: "room", method: "get"}, + {name: "Payments", relation: "payment", method: "get"}] + } + resource function get locations() returns Location { + return {name: "Cinnamon Lodge", id: "1001", address: "Habarana"}; + } + + @http:ResourceConfig { + name: "Rooms" + } + resource function get locations/[string id]/rooms() returns error? { + return; + } + + @http:ResourceConfig { + name: "Payments" + } + resource function get locations/[string id]/payments() returns error? { + return; + } +} From 576af53052729bf682a928b2cd34aed0272a2ea5 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 8 Jan 2024 10:15:34 +0530 Subject: [PATCH 30/85] Fix failing tests and checkstyle violations --- .../openapi/service/mapper/OpenAPIResourceMapper.java | 7 ++----- .../openapi/service/mapper/parameter/HateoasMapper.java | 2 +- .../expected_gen/hateoas/hateoas_multiple_links.yaml | 4 ++-- .../hateoas/hateoas_multiple_links.bal | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java index b74711f3f..e0734fe49 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIResourceMapper.java @@ -32,7 +32,6 @@ import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.IncompatibleResourceDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; -import io.ballerina.openapi.service.mapper.hateoas.Resource; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OperationAdaptor; import io.ballerina.openapi.service.mapper.parameter.HateoasMapper; @@ -245,8 +244,8 @@ private Optional convertResourceToOperation(FunctionDefinition return Optional.of(op); } - private void setSwaggerLinksInApiResponse(SemanticModel semanticModel, ServiceDeclarationNode service, ApiResponses apiResponses, - FunctionDefinitionNode resource) { + private void setSwaggerLinksInApiResponse(SemanticModel semanticModel, ServiceDeclarationNode service, + ApiResponses apiResponses, FunctionDefinitionNode resource) { Optional serviceDeclarationOpt = semanticModel.symbol(service); ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); int serviceId = serviceSymbol.hashCode(); @@ -256,8 +255,6 @@ private void setSwaggerLinksInApiResponse(SemanticModel semanticModel, ServiceDe int statusCode = Integer.parseInt(entry.getKey()); if (statusCode >= 200 && statusCode < 300) { entry.getValue().setLinks(swaggerLinks); - ApiResponse apiResponse = new ApiResponse(); - apiResponse.setLinks(swaggerLinks); } } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index dca8fb98f..d43134600 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -60,7 +60,7 @@ public Map mapHateoasLinksToSwaggerLinks(int serviceId, private List getLinks(String linkedTo) { List links = new ArrayList<>(); - String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split("},\\\\s*"); + String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split("\\},\\s*"); for (String linkString : linkArray) { HateoasLink link = parseHateoasLink(linkString); links.add(link); diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml index a85dcfcb1..e441734ee 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_multiple_links.yaml @@ -21,10 +21,10 @@ paths: schema: $ref: '#/components/schemas/Location' links: - room: - operationId: getLocationsIdRooms payment: operationId: getLocationsIdPayments + room: + operationId: getLocationsIdRooms /locations/{id}/rooms: get: operationId: getLocationsIdRooms diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal index 2becb1ece..f1cd84571 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal @@ -26,7 +26,7 @@ service /payloadV on new http:Listener(9090) { @http:ResourceConfig { name: "Locations", linkedTo: [ {name: "Rooms", relation: "room", method: "get"}, - {name: "Payments", relation: "payment", method: "get"}] + {name: "Payments", relation: "payment", method: "get"}] } resource function get locations() returns Location { return {name: "Cinnamon Lodge", id: "1001", address: "Habarana"}; From f5fc72bfb0f2844f2a4a1f361e8c26ebaf444970 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 8 Jan 2024 14:25:35 +0530 Subject: [PATCH 31/85] Add test cases --- .../mapper/parameter/HateoasMapper.java | 6 +- .../generators/openapi/HateoasTests.java | 6 ++ .../hateoas/hateoas_self_rel.yaml | 87 +++++++++++++++++++ .../hateoas/hateoas_self_rel.bal | 40 +++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index d43134600..d5f57329f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -81,7 +81,11 @@ public static HateoasLink parseHateoasLink(String input) { } } hateoasLink.setResourceName(keyValueMap.get("name")); - hateoasLink.setRel(keyValueMap.get("relation")); + if (keyValueMap.get("relation") == null) { + hateoasLink.setRel("self"); + } else { + hateoasLink.setRel(keyValueMap.get("relation")); + } hateoasLink.setResourceMethod(keyValueMap.get("method")); return hateoasLink; } diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java index ae8c28c07..4cb5bb14c 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -37,4 +37,10 @@ public void testHateoasMultipleLinks() throws IOException { Path ballerinafilePath = RES_DIR.resolve("hateoas/hateoas_multiple_links.bal"); TestUtils.compareWithGeneratedFile(ballerinafilePath, "hateoas/hateoas_multiple_links.yaml"); } + + @Test(description = "Self relation to a resource (default relation value)") + public void testHateoasSelfRelation() throws IOException { + Path ballerinaFilePath = RES_DIR.resolve("hateoas/hateoas_self_rel.bal"); + TestUtils.compareWithGeneratedFile(ballerinaFilePath, "hateoas/hateoas_self_rel.yaml"); + } } diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml new file mode 100644 index 000000000..1c5db6aa6 --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml @@ -0,0 +1,87 @@ +openapi: 3.0.1 +info: + title: PayloadV + version: 0.0.0 +servers: + - url: "{server}:{port}/payloadV" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /locations: + get: + operationId: getLocations + responses: + "200": + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/Location' + links: + self: + operationId: getLocationsIdRooms + /locations/{id}/rooms: + get: + operationId: getLocationsIdRooms + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "202": + description: Accepted + "500": + description: InternalServerError + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' +components: + schemas: + Location: + required: + - address + - id + - name + type: object + properties: + name: + type: string + id: + type: string + address: + type: string + ErrorPayload: + required: + - message + - method + - path + - reason + - status + - timestamp + type: object + properties: + timestamp: + type: string + status: + type: integer + format: int64 + reason: + type: string + message: + type: string + path: + type: string + method: + type: string diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal new file mode 100644 index 000000000..08e0a11e2 --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal @@ -0,0 +1,40 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +public type Location record { + string name; + string id; + string address; +}; + +service /payloadV on new http:Listener(9090) { + @http:ResourceConfig { + name: "Locations", + linkedTo: [ {name: "Rooms", method: "get"} ] + } + resource function get locations() returns Location { + return {name: "Cinnamon Lodge", id: "1001", address: "Habarana"}; + } + + @http:ResourceConfig { + name: "Rooms" + } + resource function get locations/[string id]/rooms() returns error? { + return; + } +} From dae619888f7bc569667d2f5a2c878378f439e6fa Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Tue, 9 Jan 2024 09:05:09 +0530 Subject: [PATCH 32/85] Define the get type name interface --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 3 ++- .../service/mapper/constraint/ConstraintMapper.java | 8 ++++++-- .../service/mapper/model/ModuleMemberVisitor.java | 10 ++++++++-- .../openapi/service/mapper/type/RecordTypeMapper.java | 7 ++++--- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 737deb023..10374e881 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -202,7 +202,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) // 03. Filter path and component sections in OAS. // Generate openApi string for the mentioned service name. convertServiceToOpenAPI(serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); - ConstraintMapper constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, diagnostics); + ConstraintMapper constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, semanticModel, + diagnostics); constraintMapper.addMapping(); return new OASResult(openapi, diagnostics); } else { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java index 94b193842..444a293f2 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java @@ -1,5 +1,6 @@ package io.ballerina.openapi.service.mapper.constraint; +import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.ExpressionNode; import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; @@ -44,12 +45,14 @@ public class ConstraintMapper { private final OpenAPI openAPI; private final ModuleMemberVisitor moduleMemberVisitor; + private final SemanticModel semanticModel; private final List diagnostics; - public ConstraintMapper(OpenAPI openAPI, ModuleMemberVisitor moduleMemberVisitor, + public ConstraintMapper(OpenAPI openAPI, ModuleMemberVisitor moduleMemberVisitor, SemanticModel semanticModel, List diagnostics) { this.openAPI = openAPI; this.moduleMemberVisitor = moduleMemberVisitor; + this.semanticModel = semanticModel; this.diagnostics = diagnostics; } @@ -60,7 +63,8 @@ public void addMapping() { } Map schemas = components.getSchemas(); for (Map.Entry schemaEntry : schemas.entrySet()) { - TypeDefinitionNode typeDefinitionNode = moduleMemberVisitor.getTypeDefinitionNode(schemaEntry.getKey()); + TypeDefinitionNode typeDefinitionNode = moduleMemberVisitor.getTypeDefinitionNode(schemaEntry.getKey(), + semanticModel); if (Objects.isNull(typeDefinitionNode)) { continue; } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java index c518cf940..df1e4db09 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java @@ -18,12 +18,16 @@ package io.ballerina.openapi.service.mapper.model; +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.api.symbols.Symbol; +import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.syntax.tree.ListenerDeclarationNode; import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.TypeDefinitionNode; import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; import java.util.LinkedHashSet; +import java.util.Optional; import java.util.Set; /** @@ -50,9 +54,11 @@ public Set getListenerDeclarationNodes() { return listenerDeclarationNodes; } - public TypeDefinitionNode getTypeDefinitionNode(String typeName) { + public TypeDefinitionNode getTypeDefinitionNode(String typeName, SemanticModel semanticModel) { for (TypeDefinitionNode typeDefinitionNode : typeDefinitionNodes) { - if (MapperCommonUtils.unescapeIdentifier(typeDefinitionNode.typeName().text()).equals(typeName)) { + Optional symbol = semanticModel.symbol(typeDefinitionNode); + if (symbol.isPresent() && symbol.get() instanceof TypeSymbol typeSymbol && + MapperCommonUtils.getTypeName(typeSymbol).equals(typeName)) { return typeDefinitionNode; } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java index 026df8511..9ffa19c24 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java @@ -16,6 +16,7 @@ package io.ballerina.openapi.service.mapper.type; +import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.IntersectionTypeSymbol; import io.ballerina.compiler.api.symbols.RecordFieldSymbol; import io.ballerina.compiler.api.symbols.RecordTypeSymbol; @@ -139,7 +140,7 @@ public static Map mapRecordFields(Map } if (recordFieldSymbol.hasDefaultValue()) { Object recordFieldDefaultValue = getRecordFieldDefaultValue(recordName, recordFieldName, - additionalData.moduleMemberVisitor()); + additionalData.semanticModel(), additionalData.moduleMemberVisitor()); if (Objects.nonNull(recordFieldDefaultValue)) { TypeMapper.setDefaultValue(recordFieldSchema, recordFieldDefaultValue); } else { @@ -154,9 +155,9 @@ public static Map mapRecordFields(Map return properties; } - public static Object getRecordFieldDefaultValue(String recordName, String fieldName, + public static Object getRecordFieldDefaultValue(String recordName, String fieldName, SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor) { - TypeDefinitionNode recordDefNode = moduleMemberVisitor.getTypeDefinitionNode(recordName); + TypeDefinitionNode recordDefNode = moduleMemberVisitor.getTypeDefinitionNode(recordName, semanticModel); if (Objects.isNull(recordDefNode) || !(recordDefNode.typeDescriptor() instanceof RecordTypeDescriptorNode)) { return null; } From dfd8b90677feb6d14d064fc589d4a904e815af8d Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 9 Jan 2024 10:25:07 +0530 Subject: [PATCH 33/85] Improve default self relation mapping --- .../openapi/service/mapper/parameter/HateoasMapper.java | 2 +- .../expected_gen/hateoas/hateoas_self_rel.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index d5f57329f..a01b5c862 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -82,7 +82,7 @@ public static HateoasLink parseHateoasLink(String input) { } hateoasLink.setResourceName(keyValueMap.get("name")); if (keyValueMap.get("relation") == null) { - hateoasLink.setRel("self"); + hateoasLink.setRel("_self"); } else { hateoasLink.setRel(keyValueMap.get("relation")); } diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml index 1c5db6aa6..7f04fe77d 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/hateoas_self_rel.yaml @@ -21,7 +21,7 @@ paths: schema: $ref: '#/components/schemas/Location' links: - self: + _self: operationId: getLocationsIdRooms /locations/{id}/rooms: get: From fe2858287e8dedb0cd39e571791acf1466b0b8e7 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 9 Jan 2024 12:36:08 +0530 Subject: [PATCH 34/85] Add snowpeak example to the tests --- .../openapi/service/mapper/Constants.java | 1 + .../mapper/parameter/HateoasMapper.java | 3 +- .../generators/openapi/HateoasTests.java | 6 + .../hateoas/snowpeak_hateoas.yaml | 210 ++++++++++++++++++ .../hateoas/snowpeak_hateoas.bal | 92 ++++++++ 5 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml create mode 100644 openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java index eb7257986..4c388191a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java @@ -61,6 +61,7 @@ public final class Constants { public static final String OPTIONS = "OPTIONS"; public static final String HEAD = "HEAD"; public static final String OPENAPI_SUFFIX = "_openapi"; + public static final String OPENAPI_LINK_DEFAULT_REL = "_self"; public static final String SERVER = "server"; public static final String PORT = "port"; public static final String APPLICATION_PREFIX = "application/"; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index a01b5c862..bd0971ed8 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Optional; +import static io.ballerina.openapi.service.mapper.Constants.OPENAPI_LINK_DEFAULT_REL; import static io.ballerina.openapi.service.mapper.hateoas.ContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; @@ -82,7 +83,7 @@ public static HateoasLink parseHateoasLink(String input) { } hateoasLink.setResourceName(keyValueMap.get("name")); if (keyValueMap.get("relation") == null) { - hateoasLink.setRel("_self"); + hateoasLink.setRel(OPENAPI_LINK_DEFAULT_REL); } else { hateoasLink.setRel(keyValueMap.get("relation")); } diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java index 4cb5bb14c..c2662db49 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -43,4 +43,10 @@ public void testHateoasSelfRelation() throws IOException { Path ballerinaFilePath = RES_DIR.resolve("hateoas/hateoas_self_rel.bal"); TestUtils.compareWithGeneratedFile(ballerinaFilePath, "hateoas/hateoas_self_rel.yaml"); } + + @Test(description = "Hateoas with snowpeak example") + public void testHateoasSnowpeakExample() throws IOException { + Path ballerinaFilePath = RES_DIR.resolve("hateoas/snowpeak_hateoas.bal"); + TestUtils.compareWithGeneratedFile(ballerinaFilePath, "hateoas/snowpeak_hateoas.yaml"); + } } diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml new file mode 100644 index 000000000..102af7a71 --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml @@ -0,0 +1,210 @@ +openapi: 3.0.1 +info: + title: PayloadV + version: 0.0.0 +servers: + - url: "{server}:{port}/payloadV" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /locations: + get: + operationId: getLocations + responses: + "200": + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Location' + links: + room: + operationId: getLocationsIdRooms + /locations/{id}/rooms: + get: + operationId: getLocationsIdRooms + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: startDate + in: query + required: true + schema: + type: string + - name: endDate + in: query + required: true + schema: + type: string + responses: + "200": + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Room' + links: + reservation: + operationId: postReservations + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + /reservations: + post: + operationId: postReservations + responses: + "201": + description: Created + content: + text/plain: + schema: + type: string + links: + cancel: + operationId: deleteReservationsId + edit: + operationId: putReservationsId + payment: + operationId: postReservationsId + /reservations/{id}: + put: + operationId: putReservationsId + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "200": + description: Ok + content: + text/plain: + schema: + type: string + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + post: + operationId: postReservationsId + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "201": + description: Created + content: + text/plain: + schema: + type: string + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' + delete: + operationId: deleteReservationsId + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "200": + description: Ok + content: + text/plain: + schema: + type: string + "400": + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPayload' +components: + schemas: + Location: + required: + - address + - id + - name + type: object + properties: + name: + type: string + id: + type: string + address: + type: string + Room: + required: + - category + - count + - currency + - id + - price + - status + - wifi + type: object + properties: + id: + type: string + category: + type: string + wifi: + type: boolean + status: + type: string + currency: + type: string + price: + type: integer + format: int64 + count: + type: integer + format: int64 + ErrorPayload: + required: + - message + - method + - path + - reason + - status + - timestamp + type: object + properties: + timestamp: + type: string + status: + type: integer + format: int64 + reason: + type: string + message: + type: string + path: + type: string + method: + type: string diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal new file mode 100644 index 000000000..02d83d001 --- /dev/null +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal @@ -0,0 +1,92 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +public type Location record { + string name; + string id; + string address; +}; + +public type Room record { + string id; + string category; + boolean wifi; + string status; + string currency; + int price; + int count; +}; + +service /payloadV on new http:Listener(9090) { + @http:ResourceConfig { + name: "Locations", + linkedTo: [ {name: "Rooms", relation: "room", method: "get"}] + } + resource function get locations() returns Location[] { + return [{name: "Alps", id: "l1000", address: "NC 29384, some place, switzerland"}, + {name: "Pilatus", id: "l2000", address: "NC 29444, some place, switzerland"}]; + } + + @http:ResourceConfig { + name: "Rooms", + linkedTo: [{name: "Reservations", relation: "reservation", method: "post"}] + } + resource function get locations/[string id]/rooms(string startDate, string endDate) returns Room[] { + return [{ + "id": "r1000", + "category": "DELUXE", + "capacity": 5, + "wifi": true, + "status": "AVAILABLE", + "currency": "USD", + "price": 200, + "count": 3 + }]; + } + + @http:ResourceConfig { + name: "Reservations", + linkedTo: [ {name: "DeleteReservation", relation: "cancel", method: "delete"}, + {name: "UpdateReservation", relation: "edit", method: "put"}, + {name: "PayReservation", relation: "payment", method: "post"}] + } + resource function post reservations() returns string { + return "Room Reserved!"; + } + + @http:ResourceConfig { + name: "DeleteReservation" + } + resource function delete reservations/[string id]() returns string { + return "Reservation Deleted!"; + } + + @http:ResourceConfig { + name: "UpdateReservation" + } + resource function put reservations/[string id]() returns string { + return "Reservation Updated!"; + } + + @http:ResourceConfig { + name: "PayReservation" + } + resource function post reservations/[string id]() returns string { + return "Payment Successful!"; + } +} From 5ea199cbc319d8ba0abc0f5bdd2fe5dc30f7cd14 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 9 Jan 2024 21:13:03 +0530 Subject: [PATCH 35/85] Revert "Define the get type name interface" This reverts commit dae619888f7bc569667d2f5a2c878378f439e6fa. --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 3 +-- .../service/mapper/constraint/ConstraintMapper.java | 8 ++------ .../service/mapper/model/ModuleMemberVisitor.java | 10 ++-------- .../openapi/service/mapper/type/RecordTypeMapper.java | 7 +++---- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 10374e881..737deb023 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -202,8 +202,7 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) // 03. Filter path and component sections in OAS. // Generate openApi string for the mentioned service name. convertServiceToOpenAPI(serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); - ConstraintMapper constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, semanticModel, - diagnostics); + ConstraintMapper constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, diagnostics); constraintMapper.addMapping(); return new OASResult(openapi, diagnostics); } else { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java index 444a293f2..94b193842 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/constraint/ConstraintMapper.java @@ -1,6 +1,5 @@ package io.ballerina.openapi.service.mapper.constraint; -import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.ExpressionNode; import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; @@ -45,14 +44,12 @@ public class ConstraintMapper { private final OpenAPI openAPI; private final ModuleMemberVisitor moduleMemberVisitor; - private final SemanticModel semanticModel; private final List diagnostics; - public ConstraintMapper(OpenAPI openAPI, ModuleMemberVisitor moduleMemberVisitor, SemanticModel semanticModel, + public ConstraintMapper(OpenAPI openAPI, ModuleMemberVisitor moduleMemberVisitor, List diagnostics) { this.openAPI = openAPI; this.moduleMemberVisitor = moduleMemberVisitor; - this.semanticModel = semanticModel; this.diagnostics = diagnostics; } @@ -63,8 +60,7 @@ public void addMapping() { } Map schemas = components.getSchemas(); for (Map.Entry schemaEntry : schemas.entrySet()) { - TypeDefinitionNode typeDefinitionNode = moduleMemberVisitor.getTypeDefinitionNode(schemaEntry.getKey(), - semanticModel); + TypeDefinitionNode typeDefinitionNode = moduleMemberVisitor.getTypeDefinitionNode(schemaEntry.getKey()); if (Objects.isNull(typeDefinitionNode)) { continue; } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java index df1e4db09..c518cf940 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ModuleMemberVisitor.java @@ -18,16 +18,12 @@ package io.ballerina.openapi.service.mapper.model; -import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.api.symbols.Symbol; -import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.syntax.tree.ListenerDeclarationNode; import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.TypeDefinitionNode; import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; import java.util.LinkedHashSet; -import java.util.Optional; import java.util.Set; /** @@ -54,11 +50,9 @@ public Set getListenerDeclarationNodes() { return listenerDeclarationNodes; } - public TypeDefinitionNode getTypeDefinitionNode(String typeName, SemanticModel semanticModel) { + public TypeDefinitionNode getTypeDefinitionNode(String typeName) { for (TypeDefinitionNode typeDefinitionNode : typeDefinitionNodes) { - Optional symbol = semanticModel.symbol(typeDefinitionNode); - if (symbol.isPresent() && symbol.get() instanceof TypeSymbol typeSymbol && - MapperCommonUtils.getTypeName(typeSymbol).equals(typeName)) { + if (MapperCommonUtils.unescapeIdentifier(typeDefinitionNode.typeName().text()).equals(typeName)) { return typeDefinitionNode; } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java index 9ffa19c24..026df8511 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/RecordTypeMapper.java @@ -16,7 +16,6 @@ package io.ballerina.openapi.service.mapper.type; -import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.IntersectionTypeSymbol; import io.ballerina.compiler.api.symbols.RecordFieldSymbol; import io.ballerina.compiler.api.symbols.RecordTypeSymbol; @@ -140,7 +139,7 @@ public static Map mapRecordFields(Map } if (recordFieldSymbol.hasDefaultValue()) { Object recordFieldDefaultValue = getRecordFieldDefaultValue(recordName, recordFieldName, - additionalData.semanticModel(), additionalData.moduleMemberVisitor()); + additionalData.moduleMemberVisitor()); if (Objects.nonNull(recordFieldDefaultValue)) { TypeMapper.setDefaultValue(recordFieldSchema, recordFieldDefaultValue); } else { @@ -155,9 +154,9 @@ public static Map mapRecordFields(Map return properties; } - public static Object getRecordFieldDefaultValue(String recordName, String fieldName, SemanticModel semanticModel, + public static Object getRecordFieldDefaultValue(String recordName, String fieldName, ModuleMemberVisitor moduleMemberVisitor) { - TypeDefinitionNode recordDefNode = moduleMemberVisitor.getTypeDefinitionNode(recordName, semanticModel); + TypeDefinitionNode recordDefNode = moduleMemberVisitor.getTypeDefinitionNode(recordName); if (Objects.isNull(recordDefNode) || !(recordDefNode.typeDescriptor() instanceof RecordTypeDescriptorNode)) { return null; } From afc589d1a416a68bda5e1d0c02dfaa26837b0699 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 9 Jan 2024 21:38:31 +0530 Subject: [PATCH 36/85] Update license headers --- .../ballerina/openapi/service/mapper/hateoas/ContextHolder.java | 2 +- .../openapi/service/mapper/hateoas/HateoasMetadataVisitor.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Service.java | 2 +- .../openapi/service/mapper/parameter/HateoasMapper.java | 2 +- .../io/ballerina/openapi/generators/openapi/HateoasTests.java | 2 +- .../ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal | 2 +- .../ballerina-to-openapi/hateoas/hateoas_multiple_links.bal | 2 +- .../resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal | 2 +- .../resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java index 569e888ab..fad7ad402 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index decec0921..7dd4ffff0 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index 18c237a37..07215c9d0 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index 460e78324..dfd968829 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index bd0971ed8..1db2dfdc2 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java index c2662db49..985cfea8f 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal index acd75cbff..1609648bd 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal index f1cd84571..42c65ae2b 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal index 08e0a11e2..60dc804fd 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal index 02d83d001..1ad07caaf 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except From a47f83b4ad3d2368e8f18b5bc8a12cd06cfd92ff Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 10 Jan 2024 10:07:48 +0530 Subject: [PATCH 37/85] Update license header --- .../openapi/service/mapper/parameter/model/HateoasLink.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java index f5d114f30..f80faf4da 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/model/HateoasLink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except From e3e2682044e8d3cd2577ce5657a48a9c1e9005ab Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 12 Jan 2024 09:46:02 +0530 Subject: [PATCH 38/85] Refactor naming conventions --- ...{ContextHolder.java => HateoasContextHolder.java} | 12 ++++++------ .../mapper/hateoas/HateoasMetadataVisitor.java | 2 +- .../service/mapper/parameter/HateoasMapper.java | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/{ContextHolder.java => HateoasContextHolder.java} (88%) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java similarity index 88% rename from ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java rename to ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index fad7ad402..2e4ddcf73 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/ContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -23,19 +23,19 @@ import java.util.Objects; import java.util.Optional; -public final class ContextHolder { - private static ContextHolder instance; +public final class HateoasContextHolder { + private static HateoasContextHolder instance; private final List hateoasServices; - public ContextHolder() { + public HateoasContextHolder() { this.hateoasServices = new ArrayList<>(); } - public static ContextHolder getHateoasContextHolder() { - synchronized (ContextHolder.class) { + public static HateoasContextHolder getHateoasContextHolder() { + synchronized (HateoasContextHolder.class) { if (Objects.isNull(instance)) { - instance = new ContextHolder(); + instance = new HateoasContextHolder(); } } return instance; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index 7dd4ffff0..4b4c227b1 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -30,7 +30,7 @@ import java.util.Optional; -import static io.ballerina.openapi.service.mapper.hateoas.ContextHolder.getHateoasContextHolder; +import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 1db2dfdc2..f9a15cd37 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -31,7 +31,7 @@ import java.util.Optional; import static io.ballerina.openapi.service.mapper.Constants.OPENAPI_LINK_DEFAULT_REL; -import static io.ballerina.openapi.service.mapper.hateoas.ContextHolder.getHateoasContextHolder; +import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; From d997ab929062f9d67956568cd417e4f35aeca73a Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 12 Jan 2024 18:08:35 +0530 Subject: [PATCH 39/85] Add constraint support proposal to the docs --- .../proposals/constraint-support.md | 352 ++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 docs/ballerina-to-oas/proposals/constraint-support.md diff --git a/docs/ballerina-to-oas/proposals/constraint-support.md b/docs/ballerina-to-oas/proposals/constraint-support.md new file mode 100644 index 000000000..25569fd41 --- /dev/null +++ b/docs/ballerina-to-oas/proposals/constraint-support.md @@ -0,0 +1,352 @@ +# Proposal: Map Ballerina constraints to OpenAPI Specification + +_Owners_: [@SachinAkash01](https://github.com/SachinAkash01) +_Reviewers_: [@lnash94](https://github.com/lnash94) [@TharmiganK](https://github.com/TharmiganK) +_Created_: 2023/09/08 +_Updated_: 2023/09/21 +_Issue_: [#4788](https://github.com/ballerina-platform/ballerina-library/issues/4788) + +## Summary +Implement the capabilities to support constraint validations in the generated OpenAPI specification of the Ballerina +OpenAPI tool. + +## Goals +- Enhance the Ballerina OpenAPI tool by adding support for constraint validations in the generated OpenAPI +specification. + +## Motivation +OpenAPI is a widely used standard for documenting APIs. It allows developers to specify the structure and data types +expected in API requests and responses. One of its valuable features is built-in schema validation, which ensures that +the data exchanged between different software components conforms to the defined structure and types. + +Constraints are the OpenAPI schema validations equivalent in the Ballerina programming language. The existing tool for +generating OpenAPI specification from Ballerina code lacks support for including these constraints in the OpenAPI +specification. This means that when developers use constraints in their Ballerina code, this information is not properly +reflected in the OpenAPI specification. + +Overall, improving the OpenAPI tool to support Ballerina constraints in the generated OpenAPI specification is a +worthwhile investment that will improve the overall developer experience. + +## Description +The feature implementation focuses on integrating Ballerina constraints into generated OpenAPI specifications to +accurately document the API. Following is the proposed list of Ballerina constraint types and the corresponding +OpenAPI schema validations. + +**1. OpenAPI data type: integer (formats: int32, int64) : (ballerina mapping): int** + + + +
+ +| Ballerina Mapping | Keywords | +|-------------------------------------------------| -- | +| `@constraint:Int { minValue: }` | minimum | +| `@constraint:Int { maxValue: }` | maximum | +| `@constraint:Int { minValueExclusive: }` | exclusiveMinimum | +| `@constraint:Int { maxValueExclusive: }` | exclusiveMaximum | +
+ + + +1.1. Sample Ballerina Code: +```ballerina +import ballerina/http; +import ballerina/constraint; + +@constraint:Int{ + minValue: 5, + maxValue: 20 +} +public type Age int; + +type Person record{ + Age age?; +}; + +service / on new http:Listener(9090){ + resource function post newPerson(Person body) returns error?{ + return; + } +} +``` + +1.2. Generated OpenAPI Specification: +```yaml +components: + schemas: + Age: + minimum: 5 + maximum: 20 + type: integer + format: int32 + Person: + type: object + properties: + age: + $ref: '#/components/schemas/Age' +``` + +**2. OpenAPI data type: number (format: float) : (ballerina mapping): float** + + + +
+ +| Ballerina Mapping | Keywords | +|---------------------------------------------------| -- | +| `@constraint:Float { minValue: }` | minimum | +| `@constraint:Float { maxValue: }` | maximum | +| `@constraint:Float { minValueExclusive: }` | exclusiveMinimum | +| `@constraint:Float { maxValueExclusive: }` | exclusiveMaximum | +
+ + + +2.1. Ballerina Sample Code: +```ballerina +import ballerina/http; +import ballerina/constraint; + +@constraint:Float{ + maxValue: 1000.5 +} +public type Salary float; + +type Person record{ + Salary salary?; +}; + +service / on new http:Listener(9090){ + resource function post newPerson(Person body) returns error?{ + return; + } +} +``` + +2.2. Generated OpenAPI Specification: +```yaml +components: + schemas: + Salary: + maximum: 1000.5 + type: number + format: float + Person: + type: object + properties: + salary: + $ref: '#/components/schemas/Salary' +``` + +**3. OpenAPI data type: number (format: decimal) : (ballerina mapping): decimal** + + + +
+ +| Ballerina Mapping | Keywords | +|----------------------------------------------------| -- | +| `@constraint:Number { minValue: }` | minimum | +| `@constraint:Number { maxValue: }` | maximum | +| `@constraint:Number { minValueExclusive: }` | exclusiveMinimum | +| `@constraint:Number { maxValueExclusive: }` | exclusiveMaximum | +
+ + + +3.1. Sample Ballerina Code: +```ballerina +import ballerina/http; +import ballerina/constraint; + +@constraint:Number{ + maxValueExclusive: 5.1 +} +public type Rating decimal; + +type Hotel record{ + Rating rate?; +}; + +service / on new http:Listener(9090){ + resource function post newHotel(Hotel body) returns error?{ + return; + } +} +``` + +3.2. Generated OpenAPI Specification: +```yaml +components: + schemas: + Rating: + maximum: 5.1 + exclusiveMaximum: true + type: number + format: decimal + Hotel: + type: object + properties: + rate: + $ref: '#/components/schemas/Rating' +``` + +**4. OpenAPI data type: string : (ballerina mapping): string** + + + +
+ +| Ballerina Mapping | Keywords | +|--------------------------------------------| -- | +| `@constraint:String { minLength: }` | minLength | +| `@constraint:String { maxLength: }` | maxLength | +| `@constraint:String { length: }` | minLength: ``, maxLength: `` | +| `@constraint:String { pattern: }` | pattern | +
+ + + +4.1.1. Sample Ballerina Code (minLength, maxLength, pattern): +```ballerina +import ballerina/http; +import ballerina/constraint; + +@constraint:String{ + minLength: 5, + maxLength: 20, + pattern: re `^[a-zA-Z0-9_]+$` +} +public type Username string; + +type Person record{ + Username username?; +}; + +service / on new http:Listener(9090){ + resource function post newUser(Person body) returns error?{ + return; + } +} +``` + +4.1.2. Generated OpenAPI Specification: +```yaml +components: + schemas: + Username: + minLength: 3 + maxLength: 20 + pattern: "^[a-zA-Z0-9_]+$" + type: string + Person: + type: object + properties: + username: + $ref: '#/components/schemas/Username' +``` + +4.2.1. Sample Ballerina Code (length): +```ballerina +import ballerina/http; +import ballerina/constraint; + +@constraint:String{ + length: 5 +} +public type ID string; + +type Employee record{ + ID id; +}; + +service / on new http:Listener(9090){ + resource function post newEmployee(Employee body) returns error?{ + return; + } +} +``` + +4.2.2. Generated OpenAPI Specification: +```yaml +components: + schemas: + ID: + minLength: 5 + maxLength: 5 + type: string + Employee: + type: object + properties: + id: + $ref: '#/components/schemas/ID' +``` + +**5. OpenAPI data type: array : (ballerina mapping): array** + + + +
+ +| Ballerina Mapping | Keywords | +|---------------------------------------------| -- | +| `@constraint:Array { minLength: }` | minItems | +| `@constraint:Array { maxLength: }` | maxItems | +| `@constraint:Array { length: }` | minItems: ``, maxItems: `` | + +
+ + + +5.1. Sample Ballerina Code: +```ballerina +import ballerina/http; +import ballerina/constraint; + +@constraint:String{ + maxLength: 23 +} +public type HobbyItemsString string; + +@constraint:Array{ + minLength: 2, + maxLength: 5 +} +public type Hobby HobbyItemsString[]; + +public type person record{ + Hobby hobby?; +}; + +service / on new http:Listener(9090){ + resource function post hobby(Person body) returns error?{ + return; + } +} +``` + +5.2. Generated OpenAPI Specification: +```yaml +components: + schemas: + HobbyItemsString: + maxLength: 23 + type: string + Hobby: + minLength: 2 + maxLength: 5 + type: array + items: + $ref: '#/components/schemas/HobbyItemsString' + Person: + type: object + properties: + hobby: + $ref: '#/components/schemas/Hobby' +``` + +## Testing +- **Unit Testing:** evaluate the individual components and core logic of the Ballerina OpenAPI tool, focusing on +functions, methods, and modules to ensure correctness and constraint handling. +- **Integration Testing:** assess the interactions and collaborations between various modules and components of the tool, +verifying the seamless integration of data validation constraints and rule generation into the OpenAPI specification. From 89e36f02854febcb49fbec3493ef3c6c05db294e Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Tue, 16 Jan 2024 11:10:01 +0530 Subject: [PATCH 40/85] Commit suggestions Co-authored-by: Ayesh Almeida <77491511+ayeshLK@users.noreply.github.com> --- docs/ballerina-to-oas/proposals/constraint-support.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ballerina-to-oas/proposals/constraint-support.md b/docs/ballerina-to-oas/proposals/constraint-support.md index 25569fd41..6b3f2da72 100644 --- a/docs/ballerina-to-oas/proposals/constraint-support.md +++ b/docs/ballerina-to-oas/proposals/constraint-support.md @@ -1,7 +1,7 @@ # Proposal: Map Ballerina constraints to OpenAPI Specification -_Owners_: [@SachinAkash01](https://github.com/SachinAkash01) -_Reviewers_: [@lnash94](https://github.com/lnash94) [@TharmiganK](https://github.com/TharmiganK) +_Owners_: @SachinAkash01 +_Reviewers_: @lnash94 @TharmiganK _Created_: 2023/09/08 _Updated_: 2023/09/21 _Issue_: [#4788](https://github.com/ballerina-platform/ballerina-library/issues/4788) From 4586bcc3f9c3aba21363ba29217073e92c647eff Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 16 Jan 2024 14:51:38 +0530 Subject: [PATCH 41/85] Fix checkstyle errors --- .../openapi/service/mapper/OpenAPIServiceMapper.java | 0 .../openapi/service/mapper/ResourceMapper.java | 11 ++++++----- .../service/mapper/ServiceToOpenAPIMapper.java | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/OpenAPIServiceMapper.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index cf48ed41a..a8cf4d6f4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -97,8 +97,8 @@ public void addMapping(SemanticModel semanticModel, ServiceDeclarationNode servi openAPI.setPaths(pathObject); } - private void generateResourceMapping(SemanticModel semanticModel, FunctionDefinitionNode resource, Components components, - ServiceDeclarationNode service) { + private void generateResourceMapping(SemanticModel semanticModel, FunctionDefinitionNode resource, + Components components, ServiceDeclarationNode service) { String relativePath = MapperCommonUtils.generateRelativePath(resource); String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); String httpMethod = resource.functionName().toString().trim(); @@ -108,8 +108,8 @@ private void generateResourceMapping(SemanticModel semanticModel, FunctionDefini resource.location()); additionalData.diagnostics().add(error); } else { - Optional operationDTO = convertResourceToOperation(semanticModel, resource, httpMethod, components, - cleanResourcePath, service); + Optional operationDTO = convertResourceToOperation(semanticModel, resource, httpMethod, + components, cleanResourcePath, service); if (operationDTO.isPresent()) { Operation operation = operationDTO.get().getOperation(); generatePathItem(httpMethod, pathObject, operation, cleanResourcePath); @@ -185,7 +185,8 @@ private void generatePathItem(String httpMethod, Paths path, Operation operation * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(SemanticModel semanticModel, FunctionDefinitionNode resource, String httpMethod, + private Optional convertResourceToOperation(SemanticModel semanticModel, + FunctionDefinitionNode resource, String httpMethod, Components components, String generateRelativePath, ServiceDeclarationNode service) { OperationDTO op = new OperationDTO(); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 2f7e30bd5..f70eed6bb 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -36,10 +36,10 @@ import io.ballerina.openapi.service.mapper.diagnostic.ExceptionDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.AdditionalData; -import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; +import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.projects.Module; import io.ballerina.projects.Project; import io.swagger.v3.oas.models.OpenAPI; From 6e51648986b720abbde5a15ae8003f6c75318bd2 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 16 Jan 2024 15:08:15 +0530 Subject: [PATCH 42/85] Fix checkstyle violations --- .../mapper/ServiceToOpenAPIMapper.java | 2 +- .../mapper/parameter/ResponseMapper.java | 20 +++++++++---------- .../mapper/utils/MapperCommonUtils.java | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index f70eed6bb..1ab6b3ad7 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -35,11 +35,11 @@ import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.ExceptionDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; +import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.openapi.service.mapper.model.AdditionalData; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; -import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.projects.Module; import io.ballerina.projects.Project; import io.swagger.v3.oas.models.OpenAPI; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java index 37e7ebfa0..0efa215df 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java @@ -17,19 +17,19 @@ package io.ballerina.openapi.service.mapper.parameter; import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.api.symbols.Symbol; -import io.ballerina.compiler.api.symbols.TypeSymbol; -import io.ballerina.compiler.api.symbols.ResourceMethodSymbol; -import io.ballerina.compiler.api.symbols.UnionTypeSymbol; -import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; -import io.ballerina.compiler.api.symbols.IntersectionTypeSymbol; -import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; -import io.ballerina.compiler.api.symbols.RecordTypeSymbol; -import io.ballerina.compiler.api.symbols.RecordFieldSymbol; import io.ballerina.compiler.api.symbols.ClassSymbol; -import io.ballerina.compiler.api.symbols.TypeDescKind; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; +import io.ballerina.compiler.api.symbols.IntersectionTypeSymbol; +import io.ballerina.compiler.api.symbols.RecordFieldSymbol; +import io.ballerina.compiler.api.symbols.RecordTypeSymbol; +import io.ballerina.compiler.api.symbols.ResourceMethodSymbol; +import io.ballerina.compiler.api.symbols.Symbol; +import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; +import io.ballerina.compiler.api.symbols.TypeDescKind; +import io.ballerina.compiler.api.symbols.TypeSymbol; +import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; +import io.ballerina.compiler.api.symbols.UnionTypeSymbol; import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.NodeList; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java index fd2bb0b0e..309a17061 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java @@ -37,15 +37,15 @@ import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.BasicLiteralNode; import io.ballerina.compiler.syntax.tree.ExpressionNode; +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.ListConstructorExpressionNode; import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; import io.ballerina.compiler.syntax.tree.MappingFieldNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode; import io.ballerina.compiler.syntax.tree.ResourcePathParameterNode; -import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.MetadataNode; import io.ballerina.compiler.syntax.tree.SeparatedNodeList; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.compiler.syntax.tree.SpecificFieldNode; From adbcf0bf1207d13e3b33d747d47d3a1ad897f198 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 16 Jan 2024 15:26:58 +0530 Subject: [PATCH 43/85] Resolve checkstyle violations --- .../openapi/service/mapper/parameter/ResponseMapper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java index 0efa215df..d8ca2f0f8 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/ResponseMapper.java @@ -18,8 +18,6 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.ClassSymbol; -import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.api.symbols.IntersectionTypeSymbol; import io.ballerina.compiler.api.symbols.RecordFieldSymbol; import io.ballerina.compiler.api.symbols.RecordTypeSymbol; @@ -27,12 +25,14 @@ import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; import io.ballerina.compiler.api.symbols.TypeDescKind; -import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; +import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; -import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; import io.ballerina.compiler.syntax.tree.AnnotationNode; +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.syntax.tree.NodeList; +import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; import io.ballerina.openapi.service.mapper.model.AdditionalData; import io.ballerina.openapi.service.mapper.model.OperationDTO; import io.ballerina.openapi.service.mapper.parameter.model.CacheConfigAnnotation; From f6e213aa2070623ced91614124698ddfbffa83cf Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 16 Jan 2024 21:01:42 +0530 Subject: [PATCH 44/85] Resolve merge conflicts --- .../service/mapper/ResourceMapper.java | 30 +++--------- .../mapper/ResourceMapperInterface.java | 5 +- .../mapper/ServiceToOpenAPIMapper.java | 2 +- .../mapper/parameter/HateoasMapper.java | 2 +- .../mapper/response/ResponseMapper.java | 4 ++ .../response/ResponseMapperInterface.java | 3 ++ .../mapper/response/model/HateoasLink.java | 49 +++++++++++++++++++ .../openapi/generators/openapi/TestUtils.java | 1 + .../hateoas/snowpeak_hateoas.yaml | 25 +++++----- 9 files changed, 83 insertions(+), 38 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index 552d304a4..b442a5a12 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -64,6 +64,7 @@ public class ResourceMapper implements ResourceMapperInterface { private final Paths pathObject = new Paths(); private final AdditionalData additionalData; private final OpenAPI openAPI; + private final SemanticModel semanticModel; private final List resources; private final boolean treatNilableAsOptional; private final HateoasMapper hateoasMapper; @@ -74,6 +75,7 @@ public class ResourceMapper implements ResourceMapperInterface { ResourceMapper(OpenAPI openAPI, List resources, SemanticModel semanticModel, AdditionalData additionalData, boolean treatNilableAsOptional) { this.openAPI = openAPI; + this.semanticModel = semanticModel; this.resources = resources; this.additionalData = additionalData; this.treatNilableAsOptional = treatNilableAsOptional; @@ -109,8 +111,8 @@ private void generateResourceMapping(SemanticModel semanticModel, FunctionDefini resource.location()); additionalData.diagnostics().add(error); } else { - Optional operationBuilder = convertResourceToOperation(resource, httpMethod, cleanResourcePath, - components); + Optional operationBuilder = convertResourceToOperation(resource, httpMethod, + cleanResourcePath, components, service); if (operationBuilder.isPresent()) { Operation operation = operationBuilder.get().getOperation(); generatePathItem(httpMethod, pathObject, operation, cleanResourcePath); @@ -187,7 +189,8 @@ private void generatePathItem(String httpMethod, Paths path, Operation operation * @return Operation Adaptor object of given resource */ private Optional convertResourceToOperation(FunctionDefinitionNode resource, String httpMethod, - String generateRelativePath, Components components) { + String generateRelativePath, Components components, + ServiceDeclarationNode service) { OperationBuilder operationBuilder = new OperationBuilder(); operationBuilder.setHttpOperation(httpMethod); operationBuilder.setPath(generateRelativePath); @@ -220,6 +223,7 @@ private Optional convertResourceToOperation(FunctionDefinition ResponseMapperInterface responseMapper = new ResponseMapper(resource, operationBuilder, components, additionalData); + setSwaggerLinksInApiResponse(semanticModel, service, responseMapper.getApiResponses(), resource); responseMapper.setApiResponses(); return Optional.of(operationBuilder); } @@ -265,24 +269,4 @@ private Map listAPIDocumentations(FunctionDefinitionNode resourc } return apiDocs; } - - private String generateRelativePath(FunctionDefinitionNode resource) { - - StringBuilder relativePath = new StringBuilder(); - relativePath.append("/"); - if (!resource.relativeResourcePath().isEmpty()) { - for (Node node: resource.relativeResourcePath()) { - if (node instanceof ResourcePathParameterNode pathNode) { - relativePath.append("{"); - relativePath.append(pathNode.paramName().get()); - relativePath.append("}"); - } else if ((resource.relativeResourcePath().size() == 1) && (node.toString().trim().equals("."))) { - return relativePath.toString(); - } else { - relativePath.append(node.toString().trim()); - } - } - } - return relativePath.toString(); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java index c1e196c01..eb6ae48dc 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java @@ -17,7 +17,10 @@ */ package io.ballerina.openapi.service.mapper; +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; + public interface ResourceMapperInterface { - void addMapping(); + void addMapping(SemanticModel semanticModel, ServiceDeclarationNode serviceNode); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index cfdec7728..3479e26f4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -246,7 +246,7 @@ private static void convertServiceToOpenAPI(ServiceDeclarationNode serviceNode, } } AdditionalData additionalData = new AdditionalData(semanticModel, moduleMemberVisitor, diagnostics); - ResourceMapperInterface resourceMapper = new ResourceMapper(openAPI, resources, additionalData, + ResourceMapperInterface resourceMapper = new ResourceMapper(openAPI, resources, semanticModel, additionalData, isTreatNilableAsOptionalParameter(serviceNode)); resourceMapper.addMapping(semanticModel, serviceNode); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index f9a15cd37..67e10d0f4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -20,7 +20,7 @@ import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.openapi.service.mapper.hateoas.Resource; -import io.ballerina.openapi.service.mapper.parameter.model.HateoasLink; +import io.ballerina.openapi.service.mapper.response.model.HateoasLink; import io.swagger.v3.oas.models.links.Link; import java.util.ArrayList; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java index ffd10a28e..290d1e03b 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java @@ -105,6 +105,10 @@ public void setApiResponses() { operationBuilder.setApiResponses(apiResponses); } + public ApiResponses getApiResponses() { + return apiResponses; + } + private TypeSymbol getReturnTypeSymbol(FunctionDefinitionNode resourceNode) { Optional symbol = semanticModel.symbol(resourceNode); if (symbol.isEmpty() || !(symbol.get() instanceof ResourceMethodSymbol resourceMethodSymbol)) { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java index 32f4716f0..8bb2db4e0 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java @@ -17,7 +17,10 @@ */ package io.ballerina.openapi.service.mapper.response; +import io.swagger.v3.oas.models.responses.ApiResponses; + public interface ResponseMapperInterface { void setApiResponses(); + ApiResponses getApiResponses(); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/model/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/model/HateoasLink.java index e69de29bb..0496c1a10 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/model/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/model/HateoasLink.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.response.model; + +public class HateoasLink { + private String resourceName; + private String relation; + private String resourceMethod; + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getRel() { + return relation; + } + + public void setRel(String relation) { + this.relation = relation; + } + + public String getResourceMethod() { + return resourceMethod; + } + + public void setResourceMethod(String resourceMethod) { + this.resourceMethod = resourceMethod; + } +} diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java index bc70f1472..21bfb2812 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java @@ -70,6 +70,7 @@ public static List compareWithGeneratedFile(OASContract ballerinaFilePath, tempDir, null, false); if (Files.exists(tempDir.resolve("payloadV_openapi.yaml"))) { String generatedYaml = getStringFromGivenBalFile(tempDir, "payloadV_openapi.yaml"); + System.out.println(generatedYaml); generatedYaml = (generatedYaml.trim()).replaceAll("\\s+", ""); expectedYamlContent = (expectedYamlContent.trim()).replaceAll("\\s+", ""); Assert.assertTrue(generatedYaml.contains(expectedYamlContent)); diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml index b48b87b1a..463fdadb1 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/hateoas/snowpeak_hateoas.yaml @@ -168,6 +168,19 @@ components: type: string method: type: string + Location: + required: + - address + - id + - name + type: object + properties: + name: + type: string + id: + type: string + address: + type: string Room: required: - category @@ -195,15 +208,3 @@ components: count: type: integer format: int64 - Location: - required: - - address - - id - - name - type: object - properties: - name: - type: string - id: - type: string - address: From 00d5d2142c562e6c6fcb73bf1c24e47ac91c652a Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Tue, 16 Jan 2024 21:02:47 +0530 Subject: [PATCH 45/85] Delete docs/ballerina-to-oas/proposals/constraint-support.md --- .../proposals/constraint-support.md | 352 ------------------ 1 file changed, 352 deletions(-) delete mode 100644 docs/ballerina-to-oas/proposals/constraint-support.md diff --git a/docs/ballerina-to-oas/proposals/constraint-support.md b/docs/ballerina-to-oas/proposals/constraint-support.md deleted file mode 100644 index 6b3f2da72..000000000 --- a/docs/ballerina-to-oas/proposals/constraint-support.md +++ /dev/null @@ -1,352 +0,0 @@ -# Proposal: Map Ballerina constraints to OpenAPI Specification - -_Owners_: @SachinAkash01 -_Reviewers_: @lnash94 @TharmiganK -_Created_: 2023/09/08 -_Updated_: 2023/09/21 -_Issue_: [#4788](https://github.com/ballerina-platform/ballerina-library/issues/4788) - -## Summary -Implement the capabilities to support constraint validations in the generated OpenAPI specification of the Ballerina -OpenAPI tool. - -## Goals -- Enhance the Ballerina OpenAPI tool by adding support for constraint validations in the generated OpenAPI -specification. - -## Motivation -OpenAPI is a widely used standard for documenting APIs. It allows developers to specify the structure and data types -expected in API requests and responses. One of its valuable features is built-in schema validation, which ensures that -the data exchanged between different software components conforms to the defined structure and types. - -Constraints are the OpenAPI schema validations equivalent in the Ballerina programming language. The existing tool for -generating OpenAPI specification from Ballerina code lacks support for including these constraints in the OpenAPI -specification. This means that when developers use constraints in their Ballerina code, this information is not properly -reflected in the OpenAPI specification. - -Overall, improving the OpenAPI tool to support Ballerina constraints in the generated OpenAPI specification is a -worthwhile investment that will improve the overall developer experience. - -## Description -The feature implementation focuses on integrating Ballerina constraints into generated OpenAPI specifications to -accurately document the API. Following is the proposed list of Ballerina constraint types and the corresponding -OpenAPI schema validations. - -**1. OpenAPI data type: integer (formats: int32, int64) : (ballerina mapping): int** - - - -
- -| Ballerina Mapping | Keywords | -|-------------------------------------------------| -- | -| `@constraint:Int { minValue: }` | minimum | -| `@constraint:Int { maxValue: }` | maximum | -| `@constraint:Int { minValueExclusive: }` | exclusiveMinimum | -| `@constraint:Int { maxValueExclusive: }` | exclusiveMaximum | -
- - - -1.1. Sample Ballerina Code: -```ballerina -import ballerina/http; -import ballerina/constraint; - -@constraint:Int{ - minValue: 5, - maxValue: 20 -} -public type Age int; - -type Person record{ - Age age?; -}; - -service / on new http:Listener(9090){ - resource function post newPerson(Person body) returns error?{ - return; - } -} -``` - -1.2. Generated OpenAPI Specification: -```yaml -components: - schemas: - Age: - minimum: 5 - maximum: 20 - type: integer - format: int32 - Person: - type: object - properties: - age: - $ref: '#/components/schemas/Age' -``` - -**2. OpenAPI data type: number (format: float) : (ballerina mapping): float** - - - -
- -| Ballerina Mapping | Keywords | -|---------------------------------------------------| -- | -| `@constraint:Float { minValue: }` | minimum | -| `@constraint:Float { maxValue: }` | maximum | -| `@constraint:Float { minValueExclusive: }` | exclusiveMinimum | -| `@constraint:Float { maxValueExclusive: }` | exclusiveMaximum | -
- - - -2.1. Ballerina Sample Code: -```ballerina -import ballerina/http; -import ballerina/constraint; - -@constraint:Float{ - maxValue: 1000.5 -} -public type Salary float; - -type Person record{ - Salary salary?; -}; - -service / on new http:Listener(9090){ - resource function post newPerson(Person body) returns error?{ - return; - } -} -``` - -2.2. Generated OpenAPI Specification: -```yaml -components: - schemas: - Salary: - maximum: 1000.5 - type: number - format: float - Person: - type: object - properties: - salary: - $ref: '#/components/schemas/Salary' -``` - -**3. OpenAPI data type: number (format: decimal) : (ballerina mapping): decimal** - - - -
- -| Ballerina Mapping | Keywords | -|----------------------------------------------------| -- | -| `@constraint:Number { minValue: }` | minimum | -| `@constraint:Number { maxValue: }` | maximum | -| `@constraint:Number { minValueExclusive: }` | exclusiveMinimum | -| `@constraint:Number { maxValueExclusive: }` | exclusiveMaximum | -
- - - -3.1. Sample Ballerina Code: -```ballerina -import ballerina/http; -import ballerina/constraint; - -@constraint:Number{ - maxValueExclusive: 5.1 -} -public type Rating decimal; - -type Hotel record{ - Rating rate?; -}; - -service / on new http:Listener(9090){ - resource function post newHotel(Hotel body) returns error?{ - return; - } -} -``` - -3.2. Generated OpenAPI Specification: -```yaml -components: - schemas: - Rating: - maximum: 5.1 - exclusiveMaximum: true - type: number - format: decimal - Hotel: - type: object - properties: - rate: - $ref: '#/components/schemas/Rating' -``` - -**4. OpenAPI data type: string : (ballerina mapping): string** - - - -
- -| Ballerina Mapping | Keywords | -|--------------------------------------------| -- | -| `@constraint:String { minLength: }` | minLength | -| `@constraint:String { maxLength: }` | maxLength | -| `@constraint:String { length: }` | minLength: ``, maxLength: `` | -| `@constraint:String { pattern: }` | pattern | -
- - - -4.1.1. Sample Ballerina Code (minLength, maxLength, pattern): -```ballerina -import ballerina/http; -import ballerina/constraint; - -@constraint:String{ - minLength: 5, - maxLength: 20, - pattern: re `^[a-zA-Z0-9_]+$` -} -public type Username string; - -type Person record{ - Username username?; -}; - -service / on new http:Listener(9090){ - resource function post newUser(Person body) returns error?{ - return; - } -} -``` - -4.1.2. Generated OpenAPI Specification: -```yaml -components: - schemas: - Username: - minLength: 3 - maxLength: 20 - pattern: "^[a-zA-Z0-9_]+$" - type: string - Person: - type: object - properties: - username: - $ref: '#/components/schemas/Username' -``` - -4.2.1. Sample Ballerina Code (length): -```ballerina -import ballerina/http; -import ballerina/constraint; - -@constraint:String{ - length: 5 -} -public type ID string; - -type Employee record{ - ID id; -}; - -service / on new http:Listener(9090){ - resource function post newEmployee(Employee body) returns error?{ - return; - } -} -``` - -4.2.2. Generated OpenAPI Specification: -```yaml -components: - schemas: - ID: - minLength: 5 - maxLength: 5 - type: string - Employee: - type: object - properties: - id: - $ref: '#/components/schemas/ID' -``` - -**5. OpenAPI data type: array : (ballerina mapping): array** - - - -
- -| Ballerina Mapping | Keywords | -|---------------------------------------------| -- | -| `@constraint:Array { minLength: }` | minItems | -| `@constraint:Array { maxLength: }` | maxItems | -| `@constraint:Array { length: }` | minItems: ``, maxItems: `` | - -
- - - -5.1. Sample Ballerina Code: -```ballerina -import ballerina/http; -import ballerina/constraint; - -@constraint:String{ - maxLength: 23 -} -public type HobbyItemsString string; - -@constraint:Array{ - minLength: 2, - maxLength: 5 -} -public type Hobby HobbyItemsString[]; - -public type person record{ - Hobby hobby?; -}; - -service / on new http:Listener(9090){ - resource function post hobby(Person body) returns error?{ - return; - } -} -``` - -5.2. Generated OpenAPI Specification: -```yaml -components: - schemas: - HobbyItemsString: - maxLength: 23 - type: string - Hobby: - minLength: 2 - maxLength: 5 - type: array - items: - $ref: '#/components/schemas/HobbyItemsString' - Person: - type: object - properties: - hobby: - $ref: '#/components/schemas/Hobby' -``` - -## Testing -- **Unit Testing:** evaluate the individual components and core logic of the Ballerina OpenAPI tool, focusing on -functions, methods, and modules to ensure correctness and constraint handling. -- **Integration Testing:** assess the interactions and collaborations between various modules and components of the tool, -verifying the seamless integration of data validation constraints and rule generation into the OpenAPI specification. From b34c246ee6c7ec8c50c22f2f5a7e82563bfe0e51 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 16 Jan 2024 21:05:55 +0530 Subject: [PATCH 46/85] Resolve checkstyle violations --- .../java/io/ballerina/openapi/generators/openapi/TestUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java index 21bfb2812..bc70f1472 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java @@ -70,7 +70,6 @@ public static List compareWithGeneratedFile(OASContract ballerinaFilePath, tempDir, null, false); if (Files.exists(tempDir.resolve("payloadV_openapi.yaml"))) { String generatedYaml = getStringFromGivenBalFile(tempDir, "payloadV_openapi.yaml"); - System.out.println(generatedYaml); generatedYaml = (generatedYaml.trim()).replaceAll("\\s+", ""); expectedYamlContent = (expectedYamlContent.trim()).replaceAll("\\s+", ""); Assert.assertTrue(generatedYaml.contains(expectedYamlContent)); From 99ffc68adad541617100a00bd7ebbc81c5d86bf4 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 17 Jan 2024 11:38:28 +0530 Subject: [PATCH 47/85] Fix formats --- .../openapi/service/mapper/parameter/HateoasMapper.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 67e10d0f4..5ba1cdafe 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -82,11 +82,7 @@ public static HateoasLink parseHateoasLink(String input) { } } hateoasLink.setResourceName(keyValueMap.get("name")); - if (keyValueMap.get("relation") == null) { - hateoasLink.setRel(OPENAPI_LINK_DEFAULT_REL); - } else { - hateoasLink.setRel(keyValueMap.get("relation")); - } + hateoasLink.setRel(keyValueMap.getOrDefault("relation", OPENAPI_LINK_DEFAULT_REL)); hateoasLink.setResourceMethod(keyValueMap.get("method")); return hateoasLink; } From b6fc12b6c45ee7274a6d32df5552243478295d71 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 17 Jan 2024 11:46:01 +0530 Subject: [PATCH 48/85] Refactor hypermedia support --- .../service/mapper/ResourceMapper.java | 30 +++++++++++-------- .../mapper/ResourceMapperInterface.java | 2 +- .../mapper/ServiceToOpenAPIMapper.java | 15 ++++++---- .../mapper/hateoas/HateoasContextHolder.java | 11 +++---- .../hateoas/HateoasMetadataVisitor.java | 7 +++-- .../service/mapper/hateoas/Service.java | 8 ++++- .../mapper/parameter/HateoasMapper.java | 4 +-- 7 files changed, 47 insertions(+), 30 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index b442a5a12..b4727741a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -64,7 +64,7 @@ public class ResourceMapper implements ResourceMapperInterface { private final Paths pathObject = new Paths(); private final AdditionalData additionalData; private final OpenAPI openAPI; - private final SemanticModel semanticModel; + private final String packageId; private final List resources; private final boolean treatNilableAsOptional; private final HateoasMapper hateoasMapper; @@ -72,17 +72,17 @@ public class ResourceMapper implements ResourceMapperInterface { /** * Initializes a resource parser for openApi. */ - ResourceMapper(OpenAPI openAPI, List resources, SemanticModel semanticModel, + ResourceMapper(OpenAPI openAPI, List resources, String packageId, AdditionalData additionalData, boolean treatNilableAsOptional) { this.openAPI = openAPI; - this.semanticModel = semanticModel; + this.packageId = packageId; this.resources = resources; this.additionalData = additionalData; this.treatNilableAsOptional = treatNilableAsOptional; this.hateoasMapper = new HateoasMapper(); } - public void addMapping(SemanticModel semanticModel, ServiceDeclarationNode service) { + public void addMapping(String packageId, SemanticModel semanticModel, ServiceDeclarationNode service) { Components components = openAPI.getComponents(); if (components == null) { components = new Components(); @@ -92,7 +92,7 @@ public void addMapping(SemanticModel semanticModel, ServiceDeclarationNode servi components.setSchemas(new TreeMap<>()); } for (FunctionDefinitionNode resource : resources) { - generateResourceMapping(semanticModel, resource, components, service); + generateResourceMapping(packageId, semanticModel, resource, components, service); } if (components.getSchemas().isEmpty()) { openAPI.setComponents(null); @@ -100,7 +100,7 @@ public void addMapping(SemanticModel semanticModel, ServiceDeclarationNode servi openAPI.setPaths(pathObject); } - private void generateResourceMapping(SemanticModel semanticModel, FunctionDefinitionNode resource, + private void generateResourceMapping(String packageId, SemanticModel semanticModel, FunctionDefinitionNode resource, Components components, ServiceDeclarationNode service) { String relativePath = MapperCommonUtils.generateRelativePath(resource); String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); @@ -111,8 +111,8 @@ private void generateResourceMapping(SemanticModel semanticModel, FunctionDefini resource.location()); additionalData.diagnostics().add(error); } else { - Optional operationBuilder = convertResourceToOperation(resource, httpMethod, - cleanResourcePath, components, service); + Optional operationBuilder = convertResourceToOperation(packageId, semanticModel, resource, + httpMethod, cleanResourcePath, components, service); if (operationBuilder.isPresent()) { Operation operation = operationBuilder.get().getOperation(); generatePathItem(httpMethod, pathObject, operation, cleanResourcePath); @@ -188,7 +188,8 @@ private void generatePathItem(String httpMethod, Paths path, Operation operation * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(FunctionDefinitionNode resource, String httpMethod, + private Optional convertResourceToOperation(String packageId, SemanticModel semanticModel, + FunctionDefinitionNode resource, String httpMethod, String generateRelativePath, Components components, ServiceDeclarationNode service) { OperationBuilder operationBuilder = new OperationBuilder(); @@ -223,17 +224,20 @@ private Optional convertResourceToOperation(FunctionDefinition ResponseMapperInterface responseMapper = new ResponseMapper(resource, operationBuilder, components, additionalData); - setSwaggerLinksInApiResponse(semanticModel, service, responseMapper.getApiResponses(), resource); + + setSwaggerLinksInApiResponse(packageId, semanticModel, service, responseMapper.getApiResponses(), resource); responseMapper.setApiResponses(); return Optional.of(operationBuilder); } - private void setSwaggerLinksInApiResponse(SemanticModel semanticModel, ServiceDeclarationNode service, - ApiResponses apiResponses, FunctionDefinitionNode resource) { + private void setSwaggerLinksInApiResponse(String packageId, SemanticModel semanticModel, + ServiceDeclarationNode service, ApiResponses apiResponses, + FunctionDefinitionNode resource) { Optional serviceDeclarationOpt = semanticModel.symbol(service); ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); int serviceId = serviceSymbol.hashCode(); - Map swaggerLinks = this.hateoasMapper.mapHateoasLinksToSwaggerLinks(serviceId, resource); + Map swaggerLinks = this.hateoasMapper.mapHateoasLinksToSwaggerLinks(packageId, serviceId, + resource); if (!swaggerLinks.isEmpty()) { for (Map.Entry entry : apiResponses.entrySet()) { int statusCode = Integer.parseInt(entry.getKey()); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java index eb6ae48dc..a7a81d25f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java @@ -22,5 +22,5 @@ public interface ResourceMapperInterface { - void addMapping(SemanticModel semanticModel, ServiceDeclarationNode serviceNode); + void addMapping(String packageId, SemanticModel semanticModel, ServiceDeclarationNode serviceNode); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 3479e26f4..1a8cd03e7 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -40,8 +40,9 @@ import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; +import io.ballerina.projects.*; import io.ballerina.projects.Module; -import io.ballerina.projects.Project; +import io.ballerina.projects.Package; import io.swagger.v3.oas.models.OpenAPI; import java.nio.file.Path; @@ -204,7 +205,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) serversMapper.setServers(); // 03. Filter path and component sections in OAS. // Generate openApi string for the mentioned service name. - convertServiceToOpenAPI(serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); + String packageId = oasGenerationMetaInfo.getProject().currentPackage().packageId().id().toString(); + convertServiceToOpenAPI(packageId, serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); ConstraintMapperInterface constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, diagnostics); constraintMapper.addMapping(); @@ -234,7 +236,7 @@ public static ModuleMemberVisitor extractNodesFromProject(Project project) { return balNodeVisitor; } - private static void convertServiceToOpenAPI(ServiceDeclarationNode serviceNode, OpenAPI openAPI, + private static void convertServiceToOpenAPI(String packageId, ServiceDeclarationNode serviceNode, OpenAPI openAPI, SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor, List diagnostics) { NodeList functions = serviceNode.members(); @@ -246,9 +248,9 @@ private static void convertServiceToOpenAPI(ServiceDeclarationNode serviceNode, } } AdditionalData additionalData = new AdditionalData(semanticModel, moduleMemberVisitor, diagnostics); - ResourceMapperInterface resourceMapper = new ResourceMapper(openAPI, resources, semanticModel, additionalData, + ResourceMapperInterface resourceMapper = new ResourceMapper(openAPI, resources, packageId, additionalData, isTreatNilableAsOptionalParameter(serviceNode)); - resourceMapper.addMapping(semanticModel, serviceNode); + resourceMapper.addMapping(packageId, semanticModel, serviceNode); } private static boolean isTreatNilableAsOptionalParameter(ServiceDeclarationNode serviceNode) { @@ -270,10 +272,11 @@ private static boolean isTreatNilableAsOptionalParameter(ServiceDeclarationNode } public static void extractHateoasLinkMetadata(Project project) { + String packageId = project.currentPackage().packageId().id().toString(); project.currentPackage().moduleIds().forEach(moduleId -> { Module module = project.currentPackage().module(moduleId); SemanticModel semanticModel = project.currentPackage().getCompilation().getSemanticModel(moduleId); - HateoasMetadataVisitor hateoasMetadataVisitor = new HateoasMetadataVisitor(semanticModel); + HateoasMetadataVisitor hateoasMetadataVisitor = new HateoasMetadataVisitor(packageId, semanticModel); module.documentIds().forEach(documentId -> { SyntaxTree syntaxTreeDoc = module.document(documentId).syntaxTree(); syntaxTreeDoc.rootNode().accept(hateoasMetadataVisitor); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index 2e4ddcf73..dcab6039c 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -41,12 +41,12 @@ public static HateoasContextHolder getHateoasContextHolder() { return instance; } - public void updateHateoasResource(int serviceId, String resourceName, Resource resource) { + public void updateHateoasResource(String packageId, int serviceId, String resourceName, Resource resource) { Optional hateoasService = this.hateoasServices.stream() - .filter(svc -> svc.getServiceId() == serviceId) + .filter(svc -> packageId.equals(svc.getPackageId()) && svc.getServiceId() == serviceId) .findFirst(); if (hateoasService.isEmpty()) { - Service service = new Service(serviceId); + Service service = new Service(packageId, serviceId); service.addResource(resourceName, resource); this.hateoasServices.add(service); return; @@ -55,9 +55,10 @@ public void updateHateoasResource(int serviceId, String resourceName, Resource r service.addResource(resourceName, resource); } - public Optional getHateoasResource(int serviceId, String resourceName, String resourceMethod) { + public Optional getHateoasResource(String packageId, int serviceId, String resourceName, + String resourceMethod) { return this.hateoasServices.stream() - .filter(svc -> svc.getServiceId() == serviceId) + .filter(svc -> svc.getPackageId().equals(packageId) && svc.getServiceId() == serviceId) .findFirst() .flatMap(svc -> svc.getHateoasResourceMapping().entrySet().stream() .filter(resources -> resourceName.equals(resources.getKey())) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index 4b4c227b1..4a7182156 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -35,9 +35,11 @@ import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; public class HateoasMetadataVisitor extends NodeVisitor { + private final String packageId; private final SemanticModel semanticModel; - public HateoasMetadataVisitor(SemanticModel semanticModel) { + public HateoasMetadataVisitor(String packageId, SemanticModel semanticModel) { + this.packageId = packageId; this.semanticModel = semanticModel; } @@ -65,7 +67,8 @@ public void visit(ServiceDeclarationNode serviceNode) { } String cleanedResourceName = resourceName.get().replaceAll("\"", ""); Resource hateoasResource = new Resource(resourceMethod, operationId); - getHateoasContextHolder().updateHateoasResource(serviceId, cleanedResourceName, hateoasResource); + getHateoasContextHolder().updateHateoasResource( + packageId, serviceId, cleanedResourceName, hateoasResource); } } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index dfd968829..3a875f117 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -24,10 +24,12 @@ import java.util.Map; public class Service { + private final String packageId; private final int serviceId; private final Map> hateoasResourceMapping = new HashMap<>(); - public Service(int serviceId) { + public Service(String packageId, int serviceId) { + this.packageId = packageId; this.serviceId = serviceId; } @@ -39,6 +41,10 @@ public void addResource(String resourceName, Resource resource) { hateoasResourceMapping.put(resourceName, Arrays.asList(resource)); } + public String getPackageId() { + return packageId; + } + public int getServiceId() { return serviceId; } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 5ba1cdafe..35673418b 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -37,7 +37,7 @@ public class HateoasMapper { - public Map mapHateoasLinksToSwaggerLinks(int serviceId, + public Map mapHateoasLinksToSwaggerLinks(String packageId, int serviceId, FunctionDefinitionNode resourceFunction) { Optional linkedTo = getResourceConfigAnnotation(resourceFunction) .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); @@ -48,7 +48,7 @@ public Map mapHateoasLinksToSwaggerLinks(int serviceId, Map hateoasLinks = new HashMap<>(); for (HateoasLink link : links) { Optional resource = getHateoasContextHolder() - .getHateoasResource(serviceId, link.getResourceName(), link.getResourceMethod()); + .getHateoasResource(packageId, serviceId, link.getResourceName(), link.getResourceMethod()); if (resource.isPresent()) { Link swaggerLink = new Link(); String operationId = resource.get().operationId(); From b9c9f0f46d11c27fd250e73c10d4557ee59e5bca Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 17 Jan 2024 11:52:06 +0530 Subject: [PATCH 49/85] Fix import issues --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 1a8cd03e7..21a81c986 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -40,9 +40,8 @@ import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; -import io.ballerina.projects.*; import io.ballerina.projects.Module; -import io.ballerina.projects.Package; +import io.ballerina.projects.Project; import io.swagger.v3.oas.models.OpenAPI; import java.nio.file.Path; From 35157a094d2cc4cc1680118871374e7ab189c689 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Wed, 17 Jan 2024 13:47:57 +0530 Subject: [PATCH 50/85] Refactor the usage of semantic-model and package-id --- .../io/ballerina/openapi/service/mapper/ResourceMapper.java | 6 ++---- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index b4727741a..76d178669 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -64,7 +64,6 @@ public class ResourceMapper implements ResourceMapperInterface { private final Paths pathObject = new Paths(); private final AdditionalData additionalData; private final OpenAPI openAPI; - private final String packageId; private final List resources; private final boolean treatNilableAsOptional; private final HateoasMapper hateoasMapper; @@ -72,10 +71,9 @@ public class ResourceMapper implements ResourceMapperInterface { /** * Initializes a resource parser for openApi. */ - ResourceMapper(OpenAPI openAPI, List resources, String packageId, - AdditionalData additionalData, boolean treatNilableAsOptional) { + ResourceMapper(OpenAPI openAPI, List resources, AdditionalData additionalData, + boolean treatNilableAsOptional) { this.openAPI = openAPI; - this.packageId = packageId; this.resources = resources; this.additionalData = additionalData; this.treatNilableAsOptional = treatNilableAsOptional; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 21a81c986..922bf19c1 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -205,7 +205,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) // 03. Filter path and component sections in OAS. // Generate openApi string for the mentioned service name. String packageId = oasGenerationMetaInfo.getProject().currentPackage().packageId().id().toString(); - convertServiceToOpenAPI(packageId, serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); + convertServiceToOpenAPI( + packageId, serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); ConstraintMapperInterface constraintMapper = new ConstraintMapper(openapi, moduleMemberVisitor, diagnostics); constraintMapper.addMapping(); @@ -247,7 +248,7 @@ private static void convertServiceToOpenAPI(String packageId, ServiceDeclaration } } AdditionalData additionalData = new AdditionalData(semanticModel, moduleMemberVisitor, diagnostics); - ResourceMapperInterface resourceMapper = new ResourceMapper(openAPI, resources, packageId, additionalData, + ResourceMapperInterface resourceMapper = new ResourceMapper(openAPI, resources, additionalData, isTreatNilableAsOptionalParameter(serviceNode)); resourceMapper.addMapping(packageId, semanticModel, serviceNode); } From cf982ffe6f3bfdbdce1dcd6b02ba6aae0acfc952 Mon Sep 17 00:00:00 2001 From: lnash94 Date: Wed, 17 Jan 2024 15:14:48 +0530 Subject: [PATCH 51/85] Fix review suggestions --- .../java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java | 2 +- .../src/main/java/io/ballerina/openapi/core/GeneratorUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java b/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java index adb5c195d..c9d68c09f 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java @@ -140,7 +140,7 @@ public void testWithoutDataBinding() throws IOException { "Expected content and actual generated content is mismatched for: " + yamlPath); deleteGeneratedFiles("without-data-binding-service.bal"); } else { - Assert.fail("Service generation for All Of Schema type failed."); + Assert.fail("Service generation for low level service is failed."); } } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java index ed27f0eb3..923a5676e 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java @@ -1131,7 +1131,7 @@ private static String getPathParameterType(Schema typeSchema, String pathPara String type; if (!(isStringSchema(typeSchema) || isNumberSchema(typeSchema) || isBooleanSchema(typeSchema) || isIntegerSchema(typeSchema))) { - type = "string"; + type = STRING; LOGGER.warn("unsupported path parameter type found in the parameter `" + pathParam + "`. hence the " + "parameter type is set to string."); } else { From 0420bd893fb76780549d36394f208ed69d229662 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Thu, 18 Jan 2024 02:05:45 +0530 Subject: [PATCH 52/85] Resolve merge conflicts --- .../service/mapper/ResourceMapper.java | 5 +- .../service/mapper/ResourceMapperImpl.java | 46 +++++++++++++++---- .../mapper/ResourceMapperInterface.java | 0 .../mapper/response/ResponseMapper.java | 3 ++ .../mapper/response/ResponseMapperImpl.java | 4 ++ .../response/ResponseMapperInterface.java | 0 6 files changed, 49 insertions(+), 9 deletions(-) delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index 13b8b35af..e622b3cab 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -17,7 +17,10 @@ */ package io.ballerina.openapi.service.mapper; +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; + public interface ResourceMapper { - void setOperation(); + void setOperation(String packageId, SemanticModel semanticModel, ServiceDeclarationNode service); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 35d3af93c..c192bc199 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -17,17 +17,21 @@ */ package io.ballerina.openapi.service.mapper; +import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.Documentable; import io.ballerina.compiler.api.symbols.Documentation; +import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.ResourcePathParameterNode; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.IncompatibleResourceDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.AdditionalData; import io.ballerina.openapi.service.mapper.model.OperationInventory; +import io.ballerina.openapi.service.mapper.parameter.HateoasMapper; import io.ballerina.openapi.service.mapper.parameter.ParameterMapper; import io.ballerina.openapi.service.mapper.parameter.ParameterMapperImpl; import io.ballerina.openapi.service.mapper.response.ResponseMapper; @@ -39,6 +43,9 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.links.Link; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; import java.util.HashMap; import java.util.List; @@ -61,6 +68,7 @@ public class ResourceMapperImpl implements ResourceMapper { private final OpenAPI openAPI; private final List resources; private final boolean treatNilableAsOptional; + private final HateoasMapper hateoasMapper; /** * Initializes a resource parser for openApi. @@ -71,9 +79,10 @@ public class ResourceMapperImpl implements ResourceMapper { this.resources = resources; this.additionalData = additionalData; this.treatNilableAsOptional = treatNilableAsOptional; + this.hateoasMapper = new HateoasMapper(); } - public void setOperation() { + public void setOperation(String packageId, SemanticModel semanticModel, ServiceDeclarationNode service) { Components components = openAPI.getComponents(); if (components == null) { components = new Components(); @@ -83,7 +92,7 @@ public void setOperation() { components.setSchemas(new TreeMap<>()); } for (FunctionDefinitionNode resource : resources) { - addResourceMapping(resource, components); + addResourceMapping(packageId, semanticModel, resource, components, service); } if (components.getSchemas().isEmpty()) { openAPI.setComponents(null); @@ -91,7 +100,8 @@ public void setOperation() { openAPI.setPaths(pathObject); } - private void addResourceMapping(FunctionDefinitionNode resource, Components components) { + private void addResourceMapping(String packageId, SemanticModel semanticModel, FunctionDefinitionNode resource, + Components components, ServiceDeclarationNode service) { String path = MapperCommonUtils.unescapeIdentifier(generateRelativePath(resource)); String httpMethod = resource.functionName().toString().trim(); if (httpMethod.equals(String.format("'%s", DEFAULT)) || httpMethod.equals(DEFAULT)) { @@ -100,8 +110,8 @@ private void addResourceMapping(FunctionDefinitionNode resource, Components comp resource.location()); additionalData.diagnostics().add(error); } else { - convertResourceToOperation(resource, httpMethod, path, components).ifPresent( - operation -> addPathItem(httpMethod, pathObject, operation.getOperation(), path)); + convertResourceToOperation(packageId, semanticModel, resource, httpMethod, path, components, service) + .ifPresent(operation -> addPathItem(httpMethod, pathObject, operation.getOperation(), path)); } } @@ -173,9 +183,10 @@ private void addPathItem(String httpMethod, Paths path, Operation operation, Str * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(FunctionDefinitionNode resource, String httpMethod, - String generateRelativePath, - Components components) { + private Optional convertResourceToOperation(String packageId, SemanticModel semanticModel, + FunctionDefinitionNode resource, String httpMethod, + String generateRelativePath, Components components, + ServiceDeclarationNode service) { OperationInventory operationInventory = new OperationInventory(); operationInventory.setHttpOperation(httpMethod); operationInventory.setPath(generateRelativePath); @@ -208,10 +219,29 @@ private Optional convertResourceToOperation(FunctionDefiniti ResponseMapper responseMapper = new ResponseMapperImpl(resource, operationInventory, components, additionalData); + setSwaggerLinksInApiResponse(packageId, semanticModel, service, responseMapper.getApiResponses(), resource); responseMapper.setApiResponses(); return Optional.of(operationInventory); } + private void setSwaggerLinksInApiResponse(String packageId, SemanticModel semanticModel, + ServiceDeclarationNode service, ApiResponses apiResponses, + FunctionDefinitionNode resource) { + Optional serviceDeclarationOpt = semanticModel.symbol(service); + ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); + int serviceId = serviceSymbol.hashCode(); + Map swaggerLinks = this.hateoasMapper.mapHateoasLinksToSwaggerLinks(packageId, serviceId, + resource); + if (!swaggerLinks.isEmpty()) { + for (Map.Entry entry : apiResponses.entrySet()) { + int statusCode = Integer.parseInt(entry.getKey()); + if (statusCode >= 200 && statusCode < 300) { + entry.getValue().setLinks(swaggerLinks); + } + } + } + } + /** * Filter the API documentations from resource function node. */ diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperInterface.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java index 2d75430a8..117f56944 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java @@ -17,7 +17,10 @@ */ package io.ballerina.openapi.service.mapper.response; +import io.swagger.v3.oas.models.responses.ApiResponses; + public interface ResponseMapper { void setApiResponses(); + ApiResponses getApiResponses(); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java index 2245bf314..116200ba6 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java @@ -103,6 +103,10 @@ public void setApiResponses() { operationInventory.setApiResponses(apiResponses); } + public ApiResponses getApiResponses() { + return apiResponses; + } + private TypeSymbol getReturnTypeSymbol(FunctionDefinitionNode resourceNode) { Optional symbol = semanticModel.symbol(resourceNode); if (symbol.isEmpty() || !(symbol.get() instanceof ResourceMethodSymbol resourceMethodSymbol)) { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperInterface.java deleted file mode 100644 index e69de29bb..000000000 From d8b853331e6a40af90277ddbf82addde30279239 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Thu, 18 Jan 2024 09:01:23 +0530 Subject: [PATCH 53/85] Revert "Merge pull request #12 from ballerina-platform/master" This reverts commit fc71806a9261822f61dc5ad7aca730bce6e2cf6a, reversing changes made to 0420bd893fb76780549d36394f208ed69d229662. --- .../openapi/cmd/BallerinaCodeGenerator.java | 2 +- .../openapi/cmd/OpenApiGenServiceCmdTest.java | 32 -------- .../expected_gen/without-data-binding.bal | 11 --- .../test/resources/withoutDataBinding.yaml | 76 ------------------- .../openapi/core/GeneratorUtils.java | 47 ++---------- .../client/BallerinaClientGenerator.java | 3 +- .../service/BallerinaServiceGenerator.java | 5 +- 7 files changed, 9 insertions(+), 167 deletions(-) delete mode 100644 openapi-cli/src/test/resources/expected_gen/without-data-binding.bal delete mode 100644 openapi-cli/src/test/resources/withoutDataBinding.yaml diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java index 5b83fe25a..297277b12 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java @@ -441,7 +441,7 @@ public List generateBallerinaService(Path openAPI, String serviceNam openAPIDef, nullable, preGeneratedTypeDefNodes); String schemaContent = Formatter.format( ballerinaSchemaGenerator.generateSyntaxTree()).toSourceCode(); - if (!schemaContent.isBlank() && !generateWithoutDataBinding) { + if (!schemaContent.isBlank()) { sourceFiles.add(new GenSrcFile(GenSrcFile.GenFileType.GEN_SRC, srcPackage, TYPE_FILE_NAME, (licenseHeader.isBlank() ? DEFAULT_FILE_HEADER : licenseHeader) + schemaContent)); } diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java b/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java index c9d68c09f..c8765cfab 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/cmd/OpenApiGenServiceCmdTest.java @@ -17,10 +17,8 @@ */ package io.ballerina.openapi.cmd; -import io.ballerina.cli.launcher.BLauncherException; import org.testng.Assert; import org.testng.annotations.Test; -import picocli.CommandLine; import java.io.IOException; import java.nio.file.Files; @@ -113,34 +111,4 @@ public void testOneOfSchemaGen() throws IOException { Assert.fail("Service generation for OneOf Schema type failed."); } } - - @Test(description = "Test for --without-data-binding flag") - public void testWithoutDataBinding() throws IOException { - Path yamlPath = resourceDir.resolve(Paths.get("withoutDataBinding.yaml")); - String[] args = {"--input", yamlPath.toString(), "--without-data-binding", "-o", - this.tmpDir.toString(), "--mode", "service"}; - OpenApiCmd cmd = new OpenApiCmd(printStream, this.tmpDir); - new CommandLine(cmd).parseArgs(args); - String output = ""; - try { - cmd.execute(); - } catch (BLauncherException e) { - output = e.getDetailedMessages().get(0); - } - - Path expectedServiceFile = resourceDir.resolve(Paths.get("expected_gen", - "without-data-binding.bal")); - Stream expectedServiceLines = Files.lines(expectedServiceFile); - String expectedService = expectedServiceLines.collect(Collectors.joining("\n")); - expectedServiceLines.close(); - Assert.assertFalse(Files.exists(this.tmpDir.resolve("types.bal"))); - if (Files.exists(this.tmpDir.resolve("withoutdatabinding_service.bal"))) { - String generatedService = getStringFromFile(this.tmpDir.resolve("withoutdatabinding_service.bal")); - Assert.assertEquals(replaceWhiteSpace(generatedService), replaceWhiteSpace(expectedService), - "Expected content and actual generated content is mismatched for: " + yamlPath); - deleteGeneratedFiles("without-data-binding-service.bal"); - } else { - Assert.fail("Service generation for low level service is failed."); - } - } } diff --git a/openapi-cli/src/test/resources/expected_gen/without-data-binding.bal b/openapi-cli/src/test/resources/expected_gen/without-data-binding.bal deleted file mode 100644 index bf56b7a0a..000000000 --- a/openapi-cli/src/test/resources/expected_gen/without-data-binding.bal +++ /dev/null @@ -1,11 +0,0 @@ -// AUTO-GENERATED FILE. -// This file is auto-generated by the Ballerina OpenAPI tool. - -import ballerina/http; - -listener http:Listener ep0 = new (9090, config = {host: "localhost"}); - -service /v1 on ep0 { - resource function get coupons/[string couponCode]/[int id]/[string limits](http:Caller caller, http:Request request) returns error? { - } -} diff --git a/openapi-cli/src/test/resources/withoutDataBinding.yaml b/openapi-cli/src/test/resources/withoutDataBinding.yaml deleted file mode 100644 index 029d20c3a..000000000 --- a/openapi-cli/src/test/resources/withoutDataBinding.yaml +++ /dev/null @@ -1,76 +0,0 @@ -openapi: 3.0.1 -info: - title: V1 - version: 0.1.0 -servers: - - url: "{server}:{port}/v1" - variables: - server: - default: http://localhost - port: - default: "9090" -paths: - /coupons/{couponCode}/{id}/{limits}: - get: - operationId: getCoupon - parameters: - - $ref: '#/components/parameters/ngwCouponCodePathParam' - - $ref: '#/components/parameters/ngwCouponCodePathParam02' - - $ref: '#/components/parameters/ngwCouponCodePathParam03' - responses: - '200': - description: Successful operation, coupon was found by requested code - content: - application/json: - schema: - $ref: '#/components/schemas/Cat' -components: - parameters: - ngwCouponCodePathParam: - in: path - name: couponCode - required: true - schema: - $ref: '#/components/schemas/Coupon' - ngwCouponCodePathParam02: - in: path - name: id - required: true - schema: - $ref: '#/components/schemas/Id' - ngwCouponCodePathParam03: - in: path - name: limits - required: true - schema: - type: array - items: - type: integer - schemas: - Coupon: - type: string - Id: - $ref: '#/components/schemas/AddressNo' - AddressNo: - type: integer - Pet: - type: object - properties: - name: - type: string - tag: - type: string - required: - - name - - tag - Cat: - type: object - properties: - name: - type: string - parent: - $ref: '#/components/schemas/Pet' - petType: - $ref: '#/components/schemas/Cat' - required: - - name diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java index 923a5676e..dc0facb62 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java @@ -221,8 +221,7 @@ public static QualifiedNameReferenceNode getQualifiedNameReferenceNode(String mo * @return - node lists * @throws BallerinaOpenApiException */ - public static List getRelativeResourcePath(String path, Operation operation, List resourceFunctionDocs, - Components components, boolean isWithoutDataBinding) + public static List getRelativeResourcePath(String path, Operation operation, List resourceFunctionDocs) throws BallerinaOpenApiException { List functionRelativeResourcePath = new ArrayList<>(); @@ -242,7 +241,7 @@ public static List getRelativeResourcePath(String path, Operation operatio */ if (operation.getParameters() != null) { extractPathParameterDetails(operation, functionRelativeResourcePath, pathNode, - pathParam, resourceFunctionDocs, components, isWithoutDataBinding); + pathParam, resourceFunctionDocs); } } else if (!pathNode.isBlank()) { IdentifierToken idToken = createIdentifierToken(escapeIdentifier(pathNode.trim())); @@ -262,9 +261,7 @@ public static List getRelativeResourcePath(String path, Operation operatio } private static void extractPathParameterDetails(Operation operation, List functionRelativeResourcePath, - String pathNode, String pathParam, - List resourceFunctionDocs, - Components components, boolean isWithoutDataBinding) + String pathNode, String pathParam, List resourceFunctionDocs) throws BallerinaOpenApiException { // check whether path parameter segment has special character String[] split = pathNode.split(CLOSE_CURLY_BRACE, 2); @@ -284,10 +281,9 @@ private static void extractPathParameterDetails(Operation operation, List && parameter.getIn().equals("path")) { String paramType; if (parameter.getSchema().get$ref() != null) { - paramType = resolveReferenceType(parameter.getSchema(), components, isWithoutDataBinding, - pathParam); + paramType = getValidName(extractReferenceType(parameter.getSchema().get$ref()), true); } else { - paramType = getPathParameterType(parameter.getSchema(), pathParam); + paramType = convertOpenAPITypeToBallerina(parameter.getSchema()); if (paramType.endsWith(NILLABLE)) { throw new BallerinaOpenApiException("Path parameter value cannot be null."); } @@ -1106,37 +1102,4 @@ public static boolean isIntegerSchema(Schema fieldSchema) { public static boolean isNumberSchema(Schema fieldSchema) { return Objects.equals(GeneratorUtils.getOpenAPIType(fieldSchema), NUMBER); } - - public static String resolveReferenceType(Schema schema, Components components, boolean isWithoutDataBinding, - String pathParam) throws BallerinaOpenApiException { - String type = GeneratorUtils.extractReferenceType(schema.get$ref()); - - if (isWithoutDataBinding) { - Schema referencedSchema = components.getSchemas().get(getValidName(type, true)); - if (referencedSchema != null) { - if (referencedSchema.get$ref() != null) { - type = resolveReferenceType(referencedSchema, components, isWithoutDataBinding, pathParam); - } else { - type = getPathParameterType(referencedSchema, pathParam); - } - } - } else { - type = getValidName(type, true); - } - return type; - } - - private static String getPathParameterType(Schema typeSchema, String pathParam) - throws BallerinaOpenApiException { - String type; - if (!(isStringSchema(typeSchema) || isNumberSchema(typeSchema) || isBooleanSchema(typeSchema) - || isIntegerSchema(typeSchema))) { - type = STRING; - LOGGER.warn("unsupported path parameter type found in the parameter `" + pathParam + "`. hence the " + - "parameter type is set to string."); - } else { - type = GeneratorUtils.convertOpenAPITypeToBallerina(typeSchema); - } - return type; - } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java index 47aa8b535..f34a83f4d 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGenerator.java @@ -580,8 +580,7 @@ private FunctionDefinitionNode getClientMethodFunctionDefinitionNode(List relativeResourcePath = resourceMode ? - createNodeList(GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), - null, openAPI.getComponents(), false)) : + createNodeList(GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), null)) : createEmptyNodeList(); return createFunctionDefinitionNode(null, metadataNode, qualifierList, functionKeyWord, functionName, relativeResourcePath, diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java index c3393a31c..3de6ec406 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/service/BallerinaServiceGenerator.java @@ -247,8 +247,7 @@ private List applyFiltersForOperations(Filter filter, String path, filterOperations.contains(operation.getValue().getOperationId().trim()))) { // getRelative resource path List functionRelativeResourcePath = GeneratorUtils.getRelativeResourcePath(path, - operation.getValue(), resourceFunctionDocs, openAPI.getComponents(), - generateWithoutDataBinding); + operation.getValue(), resourceFunctionDocs); // function call FunctionDefinitionNode functionDefinitionNode = generateWithoutDataBinding ? @@ -262,7 +261,7 @@ private List applyFiltersForOperations(Filter filter, String path, } else { // getRelative resource path List relativeResourcePath = GeneratorUtils.getRelativeResourcePath(path, operation.getValue(), - resourceFunctionDocs, openAPI.getComponents(), generateWithoutDataBinding); + resourceFunctionDocs); // function call FunctionDefinitionNode resourceFunction = generateWithoutDataBinding ? generateGenericResourceFunctions(operation, From e7a3e28e13071951741e3ccaa8635a1975f0a008 Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Thu, 18 Jan 2024 15:05:01 +0530 Subject: [PATCH 54/85] Update license header Co-authored-by: Sumudu Nissanka --- .../openapi/service/mapper/hateoas/HateoasContextHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index dcab6039c..a365fe75f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at From af850bb93a0c3004845931f2806c21a817ff4ec7 Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Thu, 18 Jan 2024 15:05:10 +0530 Subject: [PATCH 55/85] Update ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java Co-authored-by: Sumudu Nissanka --- .../openapi/service/mapper/hateoas/HateoasMetadataVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index 4a7182156..bfc5e8cd4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at From 3c5e534ece5b090dbadae786f06f6d80a4dda6dc Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 19 Jan 2024 10:50:05 +0530 Subject: [PATCH 56/85] Fix failing tests --- .../openapi/service/mapper/parameter/HateoasMapper.java | 2 +- .../ballerina/openapi/service/mapper/response/HateoasLink.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java index 35673418b..c6af1fd59 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java @@ -20,7 +20,7 @@ import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.openapi.service.mapper.hateoas.Resource; -import io.ballerina.openapi.service.mapper.response.model.HateoasLink; +import io.ballerina.openapi.service.mapper.response.HateoasLink; import io.swagger.v3.oas.models.links.Link; import java.util.ArrayList; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java index 0496c1a10..75d2070b6 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.openapi.service.mapper.response.model; +package io.ballerina.openapi.service.mapper.response; public class HateoasLink { private String resourceName; From dab9951693df08788a95faa2b7055ce9b49b8ba3 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 19 Jan 2024 14:28:50 +0530 Subject: [PATCH 57/85] Remove Hateoas link mapping logic from response mapper --- .../service/mapper/ResourceMapper.java | 2 +- .../service/mapper/ResourceMapperImpl.java | 29 ++++--------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index 2b648e826..dec246139 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -25,5 +25,5 @@ */ public interface ResourceMapper { - void setOperation(String packageId, SemanticModel semanticModel, ServiceDeclarationNode service); + void setOperation(SemanticModel semanticModel, ServiceDeclarationNode service); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 9e3954bf2..38ade9aeb 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -83,7 +83,7 @@ public class ResourceMapperImpl implements ResourceMapper { this.hateoasMapper = new HateoasMapper(); } - public void setOperation(String packageId, SemanticModel semanticModel, ServiceDeclarationNode service) { + public void setOperation(SemanticModel semanticModel, ServiceDeclarationNode service) { Components components = openAPI.getComponents(); if (components == null) { components = new Components(); @@ -93,7 +93,7 @@ public void setOperation(String packageId, SemanticModel semanticModel, ServiceD components.setSchemas(new TreeMap<>()); } for (FunctionDefinitionNode resource : resources) { - addResourceMapping(packageId, semanticModel, resource, components, service); + addResourceMapping(semanticModel, resource, components, service); } if (components.getSchemas().isEmpty()) { openAPI.setComponents(null); @@ -101,7 +101,7 @@ public void setOperation(String packageId, SemanticModel semanticModel, ServiceD openAPI.setPaths(pathObject); } - private void addResourceMapping(String packageId, SemanticModel semanticModel, FunctionDefinitionNode resource, + private void addResourceMapping(SemanticModel semanticModel, FunctionDefinitionNode resource, Components components, ServiceDeclarationNode service) { String path = MapperCommonUtils.unescapeIdentifier(generateRelativePath(resource)); String httpMethod = resource.functionName().toString().trim(); @@ -111,7 +111,7 @@ private void addResourceMapping(String packageId, SemanticModel semanticModel, F resource.location()); additionalData.diagnostics().add(error); } else { - convertResourceToOperation(packageId, semanticModel, resource, httpMethod, path, components, service) + convertResourceToOperation(semanticModel, resource, httpMethod, path, components, service) .ifPresent(operation -> addPathItem(httpMethod, pathObject, operation.getOperation(), path)); } } @@ -184,7 +184,7 @@ private void addPathItem(String httpMethod, Paths path, Operation operation, Str * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(String packageId, SemanticModel semanticModel, + private Optional convertResourceToOperation(SemanticModel semanticModel, FunctionDefinitionNode resource, String httpMethod, String generateRelativePath, Components components, ServiceDeclarationNode service) { @@ -220,29 +220,10 @@ private Optional convertResourceToOperation(String packageId ResponseMapper responseMapper = new ResponseMapperImpl(resource, operationInventory, components, additionalData); - setSwaggerLinksInApiResponse(packageId, semanticModel, service, responseMapper.getApiResponses(), resource); responseMapper.setApiResponses(); return Optional.of(operationInventory); } - private void setSwaggerLinksInApiResponse(String packageId, SemanticModel semanticModel, - ServiceDeclarationNode service, ApiResponses apiResponses, - FunctionDefinitionNode resource) { - Optional serviceDeclarationOpt = semanticModel.symbol(service); - ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); - int serviceId = serviceSymbol.hashCode(); - Map swaggerLinks = this.hateoasMapper.mapHateoasLinksToSwaggerLinks(packageId, serviceId, - resource); - if (!swaggerLinks.isEmpty()) { - for (Map.Entry entry : apiResponses.entrySet()) { - int statusCode = Integer.parseInt(entry.getKey()); - if (statusCode >= 200 && statusCode < 300) { - entry.getValue().setLinks(swaggerLinks); - } - } - } - } - /** * Filter the API documentations from resource function node. */ From 63ac241d79644776e53dc2f338009c91970f6df7 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 19 Jan 2024 15:07:41 +0530 Subject: [PATCH 58/85] Add new hateoas-mapper implementation --- .../service/mapper/hateoas/HateoasMapper.java | 26 +++ .../mapper/hateoas/HateoasMapperImpl.java | 180 ++++++++++++++++++ .../mapper/parameter/HateoasMapper.java | 89 --------- 3 files changed, 206 insertions(+), 89 deletions(-) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java new file mode 100644 index 000000000..2005c9f2d --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.hateoas; + +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.swagger.v3.oas.models.OpenAPI; + +public interface HateoasMapper { + void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI); +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java new file mode 100644 index 000000000..acffbaf6f --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.openapi.service.mapper.hateoas; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; +import io.ballerina.compiler.api.symbols.Symbol; +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.Node; +import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.openapi.service.mapper.Constants; +import io.ballerina.openapi.service.mapper.response.HateoasLink; +import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.links.Link; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +import static io.ballerina.openapi.service.mapper.Constants.OPENAPI_LINK_DEFAULT_REL; +import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.generateRelativePath; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; + +public class HateoasMapperImpl implements HateoasMapper { + private final String packageId; + private final SemanticModel semanticModel; + + public HateoasMapperImpl(String packageId, SemanticModel semanticModel) { + this.packageId = packageId; + this.semanticModel = semanticModel; + } + + @Override + public void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) { + Optional serviceSymbolOpt = semanticModel.symbol(serviceNode); + if (serviceSymbolOpt.isEmpty()) { + return; + } + ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceSymbolOpt.get(); + int serviceId = serviceSymbol.hashCode(); + Paths paths = openAPI.getPaths(); + for (Node node: serviceNode.members()) { + if (!node.kind().equals(SyntaxKind.RESOURCE_ACCESSOR_DEFINITION)) { + continue; + } + FunctionDefinitionNode resource = (FunctionDefinitionNode) node; + Optional responses = getApiResponsesForResource(resource, paths); + if (responses.isEmpty()) { + continue; + } + setSwaggerLinksInApiResponse(serviceId, resource, responses.get()); + } + } + + private Optional getApiResponsesForResource(FunctionDefinitionNode resource, Paths paths) { + String resourcePath = MapperCommonUtils.unescapeIdentifier(generateRelativePath(resource)); + if (!paths.containsKey(resourcePath)) { + return Optional.empty(); + } + PathItem openApiResource = paths.get(resourcePath); + String httpMethod = resource.functionName().toString().trim(); + ApiResponses responses = null; + switch (httpMethod.trim().toUpperCase(Locale.ENGLISH)) { + case Constants.GET -> { + responses = openApiResource.getGet().getResponses(); + } + case Constants.PUT -> { + responses = openApiResource.getPut().getResponses(); + } + case Constants.POST -> { + responses = openApiResource.getPost().getResponses(); + } + case Constants.DELETE -> { + responses = openApiResource.getDelete().getResponses(); + } + case Constants.OPTIONS -> { + responses = openApiResource.getOptions().getResponses(); + } + case Constants.PATCH -> { + responses = openApiResource.getPatch().getResponses(); + } + case Constants.HEAD -> { + responses = openApiResource.getHead().getResponses(); + } + default -> { } + } + return Optional.ofNullable(responses); + } + + private void setSwaggerLinksInApiResponse(int serviceId, FunctionDefinitionNode resource, + ApiResponses apiResponses) { + Map swaggerLinks = mapHateoasLinksToSwaggerLinks(packageId, serviceId, resource); + if (!swaggerLinks.isEmpty()) { + for (Map.Entry entry : apiResponses.entrySet()) { + int statusCode = Integer.parseInt(entry.getKey()); + if (statusCode >= 200 && statusCode < 300) { + entry.getValue().setLinks(swaggerLinks); + } + } + } + } + + private Map mapHateoasLinksToSwaggerLinks(String packageId, int serviceId, + FunctionDefinitionNode resourceFunction) { + Optional linkedTo = getResourceConfigAnnotation(resourceFunction) + .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); + if (linkedTo.isEmpty()) { + return Collections.emptyMap(); + } + List links = getLinks(linkedTo.get()); + Map hateoasLinks = new HashMap<>(); + for (HateoasLink link : links) { + Optional resource = getHateoasContextHolder() + .getHateoasResource(packageId, serviceId, link.getResourceName(), link.getResourceMethod()); + if (resource.isPresent()) { + Link swaggerLink = new Link(); + String operationId = resource.get().operationId(); + swaggerLink.setOperationId(operationId); + hateoasLinks.put(link.getRel(), swaggerLink); + } + } + return hateoasLinks; + } + + private List getLinks(String linkedTo) { + List links = new ArrayList<>(); + String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split("\\},\\s*"); + for (String linkString : linkArray) { + HateoasLink link = parseHateoasLink(linkString); + links.add(link); + } + return links; + } + + private HateoasLink parseHateoasLink(String input) { + HateoasLink hateoasLink = new HateoasLink(); + HashMap keyValueMap = new HashMap<>(); + String[] keyValuePairs = input.replaceAll("[{}]", "").split(",\\s*"); + for (String pair : keyValuePairs) { + String[] parts = pair.split(":\\s*"); + if (parts.length == 2) { + String key = parts[0].trim(); + String value = parts[1].replaceAll("\"", "").trim(); + keyValueMap.put(key, value); + } + } + hateoasLink.setResourceName(keyValueMap.get("name")); + hateoasLink.setRel(keyValueMap.getOrDefault("relation", OPENAPI_LINK_DEFAULT_REL)); + hateoasLink.setResourceMethod(keyValueMap.get("method")); + return hateoasLink; + } +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java deleted file mode 100644 index c6af1fd59..000000000 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/parameter/HateoasMapper.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.ballerina.openapi.service.mapper.parameter; - -import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.openapi.service.mapper.hateoas.Resource; -import io.ballerina.openapi.service.mapper.response.HateoasLink; -import io.swagger.v3.oas.models.links.Link; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static io.ballerina.openapi.service.mapper.Constants.OPENAPI_LINK_DEFAULT_REL; -import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; -import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; -import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; - -public class HateoasMapper { - - public Map mapHateoasLinksToSwaggerLinks(String packageId, int serviceId, - FunctionDefinitionNode resourceFunction) { - Optional linkedTo = getResourceConfigAnnotation(resourceFunction) - .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); - if (linkedTo.isEmpty()) { - return Collections.emptyMap(); - } - List links = getLinks(linkedTo.get()); - Map hateoasLinks = new HashMap<>(); - for (HateoasLink link : links) { - Optional resource = getHateoasContextHolder() - .getHateoasResource(packageId, serviceId, link.getResourceName(), link.getResourceMethod()); - if (resource.isPresent()) { - Link swaggerLink = new Link(); - String operationId = resource.get().operationId(); - swaggerLink.setOperationId(operationId); - hateoasLinks.put(link.getRel(), swaggerLink); - } - } - return hateoasLinks; - } - - private List getLinks(String linkedTo) { - List links = new ArrayList<>(); - String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split("\\},\\s*"); - for (String linkString : linkArray) { - HateoasLink link = parseHateoasLink(linkString); - links.add(link); - } - return links; - } - - public static HateoasLink parseHateoasLink(String input) { - HateoasLink hateoasLink = new HateoasLink(); - HashMap keyValueMap = new HashMap<>(); - String[] keyValuePairs = input.replaceAll("[{}]", "").split(",\\s*"); - for (String pair : keyValuePairs) { - String[] parts = pair.split(":\\s*"); - if (parts.length == 2) { - String key = parts[0].trim(); - String value = parts[1].replaceAll("\"", "").trim(); - keyValueMap.put(key, value); - } - } - hateoasLink.setResourceName(keyValueMap.get("name")); - hateoasLink.setRel(keyValueMap.getOrDefault("relation", OPENAPI_LINK_DEFAULT_REL)); - hateoasLink.setResourceMethod(keyValueMap.get("method")); - return hateoasLink; - } -} From 9b939c7c27722f195d38a06c07ce59d4010c35d6 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 19 Jan 2024 15:15:56 +0530 Subject: [PATCH 59/85] Add doc-comment to the hateoas-mapper interface --- .../openapi/service/mapper/hateoas/HateoasMapper.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index 2005c9f2d..524b25968 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -21,6 +21,12 @@ import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.swagger.v3.oas.models.OpenAPI; +/** + * This {@link HateoasMapper} uses to set HATEOAS links into the OpenAPI context. + * + * @since 1.9.0 + */ public interface HateoasMapper { + void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI); } From 1ee2599c4cf963025288418e92321a40faee88c5 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 19 Jan 2024 15:16:07 +0530 Subject: [PATCH 60/85] Refactor code-base --- .../openapi/service/mapper/ResourceMapperImpl.java | 7 ------- .../service/mapper/ServiceToOpenAPIMapper.java | 11 +++++++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 38ade9aeb..512c387e0 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -20,7 +20,6 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.Documentable; import io.ballerina.compiler.api.symbols.Documentation; -import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.Node; @@ -31,7 +30,6 @@ import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.model.AdditionalData; import io.ballerina.openapi.service.mapper.model.OperationInventory; -import io.ballerina.openapi.service.mapper.parameter.HateoasMapper; import io.ballerina.openapi.service.mapper.parameter.ParameterMapper; import io.ballerina.openapi.service.mapper.parameter.ParameterMapperImpl; import io.ballerina.openapi.service.mapper.response.ResponseMapper; @@ -43,9 +41,6 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.Paths; -import io.swagger.v3.oas.models.links.Link; -import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.oas.models.responses.ApiResponses; import java.util.HashMap; import java.util.List; @@ -69,7 +64,6 @@ public class ResourceMapperImpl implements ResourceMapper { private final OpenAPI openAPI; private final List resources; private final boolean treatNilableAsOptional; - private final HateoasMapper hateoasMapper; /** * Initializes a resource parser for openApi. @@ -80,7 +74,6 @@ public class ResourceMapperImpl implements ResourceMapper { this.resources = resources; this.additionalData = additionalData; this.treatNilableAsOptional = treatNilableAsOptional; - this.hateoasMapper = new HateoasMapper(); } public void setOperation(SemanticModel semanticModel, ServiceDeclarationNode service) { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 4a3ea701d..f091c7230 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -35,6 +35,8 @@ import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.ExceptionDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; +import io.ballerina.openapi.service.mapper.hateoas.HateoasMapper; +import io.ballerina.openapi.service.mapper.hateoas.HateoasMapperImpl; import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.openapi.service.mapper.model.AdditionalData; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; @@ -205,11 +207,12 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) // 03. Filter path and component sections in OAS. // Generate openApi string for the mentioned service name. String packageId = oasGenerationMetaInfo.getProject().currentPackage().packageId().id().toString(); - convertServiceToOpenAPI( - packageId, serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); + convertServiceToOpenAPI(serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); ConstraintMapper constraintMapper = new ConstraintMapperImpl(openapi, moduleMemberVisitor, diagnostics); constraintMapper.setConstraints(); + HateoasMapper hateoasMapper = new HateoasMapperImpl(packageId, semanticModel); + hateoasMapper.setSwaggerLinks(serviceDefinition, openapi); return new OASResult(openapi, diagnostics); } else { return new OASResult(openapi, oasResult.getDiagnostics()); @@ -236,7 +239,7 @@ public static ModuleMemberVisitor extractNodesFromProject(Project project) { return balNodeVisitor; } - private static void convertServiceToOpenAPI(String packageId, ServiceDeclarationNode serviceNode, OpenAPI openAPI, + private static void convertServiceToOpenAPI(ServiceDeclarationNode serviceNode, OpenAPI openAPI, SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor, List diagnostics) { NodeList functions = serviceNode.members(); @@ -250,7 +253,7 @@ private static void convertServiceToOpenAPI(String packageId, ServiceDeclaration AdditionalData additionalData = new AdditionalData(semanticModel, moduleMemberVisitor, diagnostics); ResourceMapper resourceMapper = new ResourceMapperImpl(openAPI, resources, additionalData, isTreatNilableAsOptionalParameter(serviceNode)); - resourceMapper.setOperation(packageId, semanticModel, serviceNode); + resourceMapper.setOperation(semanticModel, serviceNode); } private static boolean isTreatNilableAsOptionalParameter(ServiceDeclarationNode serviceNode) { From 9f6645325dc172a7833e47009cf64c1936a91644 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 19 Jan 2024 15:22:04 +0530 Subject: [PATCH 61/85] Update doc-comments of the hateoas mapper --- .../openapi/service/mapper/hateoas/HateoasMapper.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index 524b25968..4c5b4fb07 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -27,6 +27,12 @@ * @since 1.9.0 */ public interface HateoasMapper { - + + /** + * Sets HATEOAS links into the OpenAPI context. + * + * @param serviceNode Specific service declaration node + * @param openAPI Current OpenAPI context + */ void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI); } From dd17f5ef4c017ef0b595c6ad75e14bbf89c6b699 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Fri, 19 Jan 2024 16:46:54 +0530 Subject: [PATCH 62/85] Remove unused function parameters --- .../openapi/service/mapper/ResourceMapperImpl.java | 14 ++++++-------- .../service/mapper/ServiceToOpenAPIMapper.java | 2 +- .../service/mapper/hateoas/HateoasMapper.java | 2 +- .../service/mapper/hateoas/HateoasMapperImpl.java | 2 +- .../service/mapper/response/ResponseMapper.java | 3 --- .../mapper/response/ResponseMapperImpl.java | 4 ---- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 512c387e0..40fa0f198 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -86,7 +86,7 @@ public void setOperation(SemanticModel semanticModel, ServiceDeclarationNode ser components.setSchemas(new TreeMap<>()); } for (FunctionDefinitionNode resource : resources) { - addResourceMapping(semanticModel, resource, components, service); + addResourceMapping(resource, components); } if (components.getSchemas().isEmpty()) { openAPI.setComponents(null); @@ -94,8 +94,7 @@ public void setOperation(SemanticModel semanticModel, ServiceDeclarationNode ser openAPI.setPaths(pathObject); } - private void addResourceMapping(SemanticModel semanticModel, FunctionDefinitionNode resource, - Components components, ServiceDeclarationNode service) { + private void addResourceMapping(FunctionDefinitionNode resource, Components components) { String path = MapperCommonUtils.unescapeIdentifier(generateRelativePath(resource)); String httpMethod = resource.functionName().toString().trim(); if (httpMethod.equals(String.format("'%s", DEFAULT)) || httpMethod.equals(DEFAULT)) { @@ -104,7 +103,7 @@ private void addResourceMapping(SemanticModel semanticModel, FunctionDefinitionN resource.location()); additionalData.diagnostics().add(error); } else { - convertResourceToOperation(semanticModel, resource, httpMethod, path, components, service) + convertResourceToOperation(resource, httpMethod, path, components) .ifPresent(operation -> addPathItem(httpMethod, pathObject, operation.getOperation(), path)); } } @@ -177,10 +176,9 @@ private void addPathItem(String httpMethod, Paths path, Operation operation, Str * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(SemanticModel semanticModel, - FunctionDefinitionNode resource, String httpMethod, - String generateRelativePath, Components components, - ServiceDeclarationNode service) { + private Optional convertResourceToOperation(FunctionDefinitionNode resource, String httpMethod, + String generateRelativePath, + Components components) { OperationInventory operationInventory = new OperationInventory(); operationInventory.setHttpOperation(httpMethod); operationInventory.setPath(generateRelativePath); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index f091c7230..4519d145b 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -274,7 +274,7 @@ private static boolean isTreatNilableAsOptionalParameter(ServiceDeclarationNode return true; } - public static void extractHateoasLinkMetadata(Project project) { + private static void extractHateoasLinkMetadata(Project project) { String packageId = project.currentPackage().packageId().id().toString(); project.currentPackage().moduleIds().forEach(moduleId -> { Module module = project.currentPackage().module(moduleId); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index 4c5b4fb07..3421ec52f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index acffbaf6f..1572b6d83 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java index eead2b829..1673466a9 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java @@ -17,8 +17,6 @@ */ package io.ballerina.openapi.service.mapper.response; -import io.swagger.v3.oas.models.responses.ApiResponses; - /** * This {@link ResponseMapper} represents the interface for response mapper. * @@ -27,5 +25,4 @@ public interface ResponseMapper { void setApiResponses(); - ApiResponses getApiResponses(); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java index 3c780eed7..00977bfd8 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapperImpl.java @@ -110,10 +110,6 @@ public void setApiResponses() { operationInventory.setApiResponses(apiResponses); } - public ApiResponses getApiResponses() { - return apiResponses; - } - private TypeSymbol getReturnTypeSymbol(FunctionDefinitionNode resourceNode) { Optional symbol = semanticModel.symbol(resourceNode); if (symbol.isEmpty() || !(symbol.get() instanceof ResourceMethodSymbol resourceMethodSymbol)) { From dae465e481efc827375e7b5d04bbcad19835990a Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 22 Jan 2024 09:24:58 +0530 Subject: [PATCH 63/85] Update license headers --- .../openapi/service/mapper/hateoas/HateoasContextHolder.java | 2 +- .../openapi/service/mapper/hateoas/HateoasMetadataVisitor.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Service.java | 2 +- .../ballerina/openapi/service/mapper/response/HateoasLink.java | 2 +- .../io/ballerina/openapi/generators/openapi/HateoasTests.java | 2 +- .../ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal | 2 +- .../ballerina-to-openapi/hateoas/hateoas_multiple_links.bal | 2 +- .../resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal | 2 +- .../resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index a365fe75f..076800133 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index bfc5e8cd4..bb21ab416 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index 07215c9d0..a6f1865fd 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index 3a875f117..b484991f9 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java index 75d2070b6..8199d463d 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java index 985cfea8f..0b4c17d15 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal index 1609648bd..cabd3937f 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal index 42c65ae2b..1c0ed1493 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal index 60dc804fd..e44368ee7 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal index 1ad07caaf..9c3831d05 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except From 7b2befaf76d899815c1659af6def29699aab2634 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 22 Jan 2024 09:30:05 +0530 Subject: [PATCH 64/85] Update license headers --- .../ballerina/openapi/service/mapper/hateoas/HateoasMapper.java | 2 +- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Service.java | 2 +- .../ballerina/openapi/service/mapper/response/HateoasLink.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index 3421ec52f..cf46f9fc2 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 1572b6d83..0de9916ba 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index a6f1865fd..174c07eb6 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index b484991f9..f1a5fa523 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java index 8199d463d..cf43e973c 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at From 4d2f941bc7a91034962cfdb2ced5196c174a8f21 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 22 Jan 2024 09:31:00 +0530 Subject: [PATCH 65/85] Refactor code base --- .../mapper/hateoas/HateoasMapperImpl.java | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index acffbaf6f..301930d11 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -49,6 +49,11 @@ import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; +/** + * This {@link HateoasMapperImpl} class represents the implementation of the {@link HateoasMapper}. + * + * @since 1.9.0 + */ public class HateoasMapperImpl implements HateoasMapper { private final String packageId; private final SemanticModel semanticModel; @@ -118,12 +123,13 @@ private Optional getApiResponsesForResource(FunctionDefinitionNode private void setSwaggerLinksInApiResponse(int serviceId, FunctionDefinitionNode resource, ApiResponses apiResponses) { Map swaggerLinks = mapHateoasLinksToSwaggerLinks(packageId, serviceId, resource); - if (!swaggerLinks.isEmpty()) { - for (Map.Entry entry : apiResponses.entrySet()) { - int statusCode = Integer.parseInt(entry.getKey()); - if (statusCode >= 200 && statusCode < 300) { - entry.getValue().setLinks(swaggerLinks); - } + if (swaggerLinks.isEmpty()) { + return; + } + for (Map.Entry entry : apiResponses.entrySet()) { + int statusCode = Integer.parseInt(entry.getKey()); + if (statusCode >= 200 && statusCode < 300) { + entry.getValue().setLinks(swaggerLinks); } } } @@ -140,12 +146,13 @@ private Map mapHateoasLinksToSwaggerLinks(String packageId, int se for (HateoasLink link : links) { Optional resource = getHateoasContextHolder() .getHateoasResource(packageId, serviceId, link.getResourceName(), link.getResourceMethod()); - if (resource.isPresent()) { - Link swaggerLink = new Link(); - String operationId = resource.get().operationId(); - swaggerLink.setOperationId(operationId); - hateoasLinks.put(link.getRel(), swaggerLink); + if (resource.isEmpty()) { + continue; } + Link swaggerLink = new Link(); + String operationId = resource.get().operationId(); + swaggerLink.setOperationId(operationId); + hateoasLinks.put(link.getRel(), swaggerLink); } return hateoasLinks; } @@ -166,11 +173,12 @@ private HateoasLink parseHateoasLink(String input) { String[] keyValuePairs = input.replaceAll("[{}]", "").split(",\\s*"); for (String pair : keyValuePairs) { String[] parts = pair.split(":\\s*"); - if (parts.length == 2) { - String key = parts[0].trim(); - String value = parts[1].replaceAll("\"", "").trim(); - keyValueMap.put(key, value); + if (parts.length != 2) { + continue; } + String key = parts[0].trim(); + String value = parts[1].replaceAll("\"", "").trim(); + keyValueMap.put(key, value); } hateoasLink.setResourceName(keyValueMap.get("name")); hateoasLink.setRel(keyValueMap.getOrDefault("relation", OPENAPI_LINK_DEFAULT_REL)); From a9c7016dc2598e21fc0f94c771b4cd816660a635 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 22 Jan 2024 09:31:16 +0530 Subject: [PATCH 66/85] Update licensing headers and doc-comments --- .../mapper/hateoas/HateoasContextHolder.java | 27 +++++++++++-------- .../hateoas/HateoasMetadataVisitor.java | 27 +++++++++++-------- .../service/mapper/hateoas/Resource.java | 27 +++++++++++-------- .../service/mapper/hateoas/Service.java | 27 +++++++++++-------- 4 files changed, 64 insertions(+), 44 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index a365fe75f..a3739ef1d 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -1,19 +1,19 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package io.ballerina.openapi.service.mapper.hateoas; @@ -23,6 +23,11 @@ import java.util.Objects; import java.util.Optional; +/** + * A context-holder to share HATEOAS meta-data information. + * + * @since 1.6.0 + */ public final class HateoasContextHolder { private static HateoasContextHolder instance; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index bfc5e8cd4..3fc2b8825 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -1,19 +1,19 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package io.ballerina.openapi.service.mapper.hateoas; @@ -34,6 +34,11 @@ import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; +/** + * Visitor to retrieve the Hateoas meta-data from resource functions within a {@link ServiceDeclarationNode}. + * + * @since 1.6.0 + */ public class HateoasMetadataVisitor extends NodeVisitor { private final String packageId; private final SemanticModel semanticModel; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index 07215c9d0..24c701fee 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -1,22 +1,27 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package io.ballerina.openapi.service.mapper.hateoas; +/** + * A context-holder to save and retrieve HATEOAS meta-data for a given resources. + * + * @since 1.6.0 + */ public record Resource(String resourceMethod, String operationId) { } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index 3a875f117..42a82b65a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -1,19 +1,19 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package io.ballerina.openapi.service.mapper.hateoas; @@ -23,6 +23,11 @@ import java.util.List; import java.util.Map; +/** + * A data class to hold service level HATEOAS meta-data. + * + * @since 1.6.0 + */ public class Service { private final String packageId; private final int serviceId; From e3030562d1952aad9b6fdb566d6afe5971cb3254 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 22 Jan 2024 09:35:18 +0530 Subject: [PATCH 67/85] Fix licensing headers --- .../openapi/service/mapper/hateoas/HateoasContextHolder.java | 2 +- .../openapi/service/mapper/hateoas/HateoasMapper.java | 4 ++-- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 2 +- .../service/mapper/hateoas/HateoasMetadataVisitor.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Service.java | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index a3739ef1d..3f915a846 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index 4c5b4fb07..cf46f9fc2 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 301930d11..471daabcf 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index 3fc2b8825..332a42686 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index 24c701fee..5627bad9a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index 42a82b65a..d39960142 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at From 814f2b9b996e061390d132ef042e6e68c7d4fed2 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 22 Jan 2024 10:02:09 +0530 Subject: [PATCH 68/85] Update Java doc --- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index 5627bad9a..92874e5ec 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -20,7 +20,8 @@ /** * A context-holder to save and retrieve HATEOAS meta-data for a given resources. - * + * @param resourceMethod http resource for the method + * @param operationId generated operationId * @since 1.6.0 */ public record Resource(String resourceMethod, String operationId) { From d7716d20cc3868dbb681b2b7c7a44dfe08450708 Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Mon, 22 Jan 2024 11:57:26 +0530 Subject: [PATCH 69/85] Update ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java Co-authored-by: Sumudu Nissanka --- .../openapi/service/mapper/hateoas/HateoasContextHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java index 3f915a846..ee8b66d44 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java @@ -26,7 +26,7 @@ /** * A context-holder to share HATEOAS meta-data information. * - * @since 1.6.0 + * @since 1.9.0 */ public final class HateoasContextHolder { private static HateoasContextHolder instance; From 53d24dabf8f1782db27a55f6a60ae2a4ff404b9a Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Mon, 22 Jan 2024 13:41:56 +0530 Subject: [PATCH 70/85] Update ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java Co-authored-by: Krishnananthalingam Tharmigan <63336800+TharmiganK@users.noreply.github.com> --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 4519d145b..9817166e7 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -212,7 +212,7 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) diagnostics); constraintMapper.setConstraints(); HateoasMapper hateoasMapper = new HateoasMapperImpl(packageId, semanticModel); - hateoasMapper.setSwaggerLinks(serviceDefinition, openapi); + hateoasMapper.setLinks(serviceDefinition, openapi); return new OASResult(openapi, diagnostics); } else { return new OASResult(openapi, oasResult.getDiagnostics()); From 6324c6578e24d5ba975bd785c0c3c2b81a29be6a Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 22 Jan 2024 14:50:21 +0530 Subject: [PATCH 71/85] Resolve review suggestions --- .../openapi/service/mapper/Constants.java | 1 - .../openapi/service/mapper/ResourceMapper.java | 2 +- .../service/mapper/ResourceMapperImpl.java | 4 +--- .../service/mapper/ServiceToOpenAPIMapper.java | 4 ++-- .../service/mapper/hateoas/HateoasConstants.java | 7 +++++++ .../service/mapper/hateoas/HateoasMapper.java | 2 +- .../service/mapper/hateoas/HateoasMapperImpl.java | 15 ++++++++------- 7 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java index 51e17e942..187d39a0c 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/Constants.java @@ -49,7 +49,6 @@ public final class Constants { public static final String OPTIONS = "OPTIONS"; public static final String HEAD = "HEAD"; public static final String OPENAPI_SUFFIX = "_openapi"; - public static final String OPENAPI_LINK_DEFAULT_REL = "_self"; public static final String SERVER = "server"; public static final String PORT = "port"; public static final String HTTP_REQUEST = "http:Request"; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index dec246139..b586b898f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -25,5 +25,5 @@ */ public interface ResourceMapper { - void setOperation(SemanticModel semanticModel, ServiceDeclarationNode service); + void setOperation(); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 40fa0f198..2cc1646ab 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -17,14 +17,12 @@ */ package io.ballerina.openapi.service.mapper; -import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.Documentable; import io.ballerina.compiler.api.symbols.Documentation; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.ResourcePathParameterNode; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.openapi.service.mapper.diagnostic.DiagnosticMessages; import io.ballerina.openapi.service.mapper.diagnostic.IncompatibleResourceDiagnostic; import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; @@ -76,7 +74,7 @@ public class ResourceMapperImpl implements ResourceMapper { this.treatNilableAsOptional = treatNilableAsOptional; } - public void setOperation(SemanticModel semanticModel, ServiceDeclarationNode service) { + public void setOperation() { Components components = openAPI.getComponents(); if (components == null) { components = new Components(); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 9817166e7..6e9147959 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -212,7 +212,7 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) diagnostics); constraintMapper.setConstraints(); HateoasMapper hateoasMapper = new HateoasMapperImpl(packageId, semanticModel); - hateoasMapper.setLinks(serviceDefinition, openapi); + hateoasMapper.setOpenApiLinks(serviceDefinition, openapi); return new OASResult(openapi, diagnostics); } else { return new OASResult(openapi, oasResult.getDiagnostics()); @@ -253,7 +253,7 @@ private static void convertServiceToOpenAPI(ServiceDeclarationNode serviceNode, AdditionalData additionalData = new AdditionalData(semanticModel, moduleMemberVisitor, diagnostics); ResourceMapper resourceMapper = new ResourceMapperImpl(openAPI, resources, additionalData, isTreatNilableAsOptionalParameter(serviceNode)); - resourceMapper.setOperation(semanticModel, serviceNode); + resourceMapper.setOperation(); } private static boolean isTreatNilableAsOptionalParameter(ServiceDeclarationNode serviceNode) { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java new file mode 100644 index 000000000..7b36c92e1 --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java @@ -0,0 +1,7 @@ +package io.ballerina.openapi.service.mapper.hateoas; + +public class HateoasConstants { + + public static final String OPENAPI_LINK_DEFAULT_REL = "_self"; + public static final String BALLERINA_LINKEDTO_KEYWORD = "linkedTo"; +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index cf46f9fc2..b97fec8f1 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -34,5 +34,5 @@ public interface HateoasMapper { * @param serviceNode Specific service declaration node * @param openAPI Current OpenAPI context */ - void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI); + void setOpenApiLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 471daabcf..697c2db01 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -43,7 +43,8 @@ import java.util.Map; import java.util.Optional; -import static io.ballerina.openapi.service.mapper.Constants.OPENAPI_LINK_DEFAULT_REL; +import static io.ballerina.openapi.service.mapper.hateoas.HateoasConstants.BALLERINA_LINKEDTO_KEYWORD; +import static io.ballerina.openapi.service.mapper.hateoas.HateoasConstants.OPENAPI_LINK_DEFAULT_REL; import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.generateRelativePath; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; @@ -64,7 +65,7 @@ public HateoasMapperImpl(String packageId, SemanticModel semanticModel) { } @Override - public void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) { + public void setOpenApiLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) { Optional serviceSymbolOpt = semanticModel.symbol(serviceNode); if (serviceSymbolOpt.isEmpty()) { return; @@ -81,7 +82,7 @@ public void setSwaggerLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) if (responses.isEmpty()) { continue; } - setSwaggerLinksInApiResponse(serviceId, resource, responses.get()); + setOpenApiLinksInApiResponse(serviceId, resource, responses.get()); } } @@ -120,9 +121,9 @@ private Optional getApiResponsesForResource(FunctionDefinitionNode return Optional.ofNullable(responses); } - private void setSwaggerLinksInApiResponse(int serviceId, FunctionDefinitionNode resource, + private void setOpenApiLinksInApiResponse(int serviceId, FunctionDefinitionNode resource, ApiResponses apiResponses) { - Map swaggerLinks = mapHateoasLinksToSwaggerLinks(packageId, serviceId, resource); + Map swaggerLinks = mapHateoasLinksToOpenApiLinks(packageId, serviceId, resource); if (swaggerLinks.isEmpty()) { return; } @@ -134,10 +135,10 @@ private void setSwaggerLinksInApiResponse(int serviceId, FunctionDefinitionNode } } - private Map mapHateoasLinksToSwaggerLinks(String packageId, int serviceId, + private Map mapHateoasLinksToOpenApiLinks(String packageId, int serviceId, FunctionDefinitionNode resourceFunction) { Optional linkedTo = getResourceConfigAnnotation(resourceFunction) - .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "linkedTo")); + .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, BALLERINA_LINKEDTO_KEYWORD)); if (linkedTo.isEmpty()) { return Collections.emptyMap(); } From 0de1125e6a4f42f0d84dc0e81a470e59a7dd622d Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 22 Jan 2024 14:59:48 +0530 Subject: [PATCH 72/85] Remove unused imports --- .../io/ballerina/openapi/service/mapper/ResourceMapper.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java index b586b898f..736c70dc0 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapper.java @@ -17,9 +17,6 @@ */ package io.ballerina.openapi.service.mapper; -import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; - /** * The {@link ResourceMapper} represents the interface for resource mapper. */ From 1461a87e5ca274fd8cc30794499c570a034529b3 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Mon, 22 Jan 2024 16:50:09 +0530 Subject: [PATCH 73/85] Refactor naming --- .../ballerina/openapi/service/mapper/ResourceMapperImpl.java | 4 ++-- .../mapper/hateoas/{HateoasConstants.java => Constants.java} | 2 +- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/{HateoasConstants.java => Constants.java} (85%) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 2cc1646ab..5455bbccc 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -101,8 +101,8 @@ private void addResourceMapping(FunctionDefinitionNode resource, Components comp resource.location()); additionalData.diagnostics().add(error); } else { - convertResourceToOperation(resource, httpMethod, path, components) - .ifPresent(operation -> addPathItem(httpMethod, pathObject, operation.getOperation(), path)); + convertResourceToOperation(resource, httpMethod, path, components).ifPresent( + operation -> addPathItem(httpMethod, pathObject, operation.getOperation(), path)); } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Constants.java similarity index 85% rename from ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java rename to ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Constants.java index 7b36c92e1..decccf15a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasConstants.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Constants.java @@ -1,6 +1,6 @@ package io.ballerina.openapi.service.mapper.hateoas; -public class HateoasConstants { +public class Constants { public static final String OPENAPI_LINK_DEFAULT_REL = "_self"; public static final String BALLERINA_LINKEDTO_KEYWORD = "linkedTo"; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 697c2db01..9c1e41990 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -43,8 +43,8 @@ import java.util.Map; import java.util.Optional; -import static io.ballerina.openapi.service.mapper.hateoas.HateoasConstants.BALLERINA_LINKEDTO_KEYWORD; -import static io.ballerina.openapi.service.mapper.hateoas.HateoasConstants.OPENAPI_LINK_DEFAULT_REL; +import static io.ballerina.openapi.service.mapper.hateoas.Constants.BALLERINA_LINKEDTO_KEYWORD; +import static io.ballerina.openapi.service.mapper.hateoas.Constants.OPENAPI_LINK_DEFAULT_REL; import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.generateRelativePath; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; From d60e728bee2fe99adf2458dd8e5ff70143c7148c Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Tue, 23 Jan 2024 09:30:54 +0530 Subject: [PATCH 74/85] Update ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java Co-authored-by: Krishnananthalingam Tharmigan <63336800+TharmiganK@users.noreply.github.com> --- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 9c1e41990..d56821c0b 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -150,7 +150,7 @@ private Map mapHateoasLinksToOpenApiLinks(String packageId, int se if (resource.isEmpty()) { continue; } - Link swaggerLink = new Link(); + Link openapiLink = new Link(); String operationId = resource.get().operationId(); swaggerLink.setOperationId(operationId); hateoasLinks.put(link.getRel(), swaggerLink); From e458073d607a52d29e51db349f677810a0e85b8a Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 23 Jan 2024 10:23:46 +0530 Subject: [PATCH 75/85] Refactor the variable names --- .../service/mapper/{response => hateoas}/HateoasLink.java | 2 +- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) rename ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/{response => hateoas}/HateoasLink.java (96%) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java similarity index 96% rename from ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java rename to ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java index cf43e973c..d33aa83c4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.openapi.service.mapper.response; +package io.ballerina.openapi.service.mapper.hateoas; public class HateoasLink { private String resourceName; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index d56821c0b..438d1b91e 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -26,7 +26,6 @@ import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.openapi.service.mapper.Constants; -import io.ballerina.openapi.service.mapper.response.HateoasLink; import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.PathItem; @@ -152,8 +151,8 @@ private Map mapHateoasLinksToOpenApiLinks(String packageId, int se } Link openapiLink = new Link(); String operationId = resource.get().operationId(); - swaggerLink.setOperationId(operationId); - hateoasLinks.put(link.getRel(), swaggerLink); + openapiLink.setOperationId(operationId); + hateoasLinks.put(link.getRel(), openapiLink); } return hateoasLinks; } From dfa05455b7fb2180d9b9ece0f445314a25553116 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 23 Jan 2024 10:25:30 +0530 Subject: [PATCH 76/85] Refactor the method for generating operationId --- .../service/mapper/ResourceMapperImpl.java | 17 ++++---------- .../hateoas/HateoasMetadataVisitor.java | 13 +---------- .../mapper/utils/MapperCommonUtils.java | 23 ++++++++++++------- 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index 5455bbccc..eaba491ec 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -174,25 +174,18 @@ private void addPathItem(String httpMethod, Paths path, Operation operation, Str * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(FunctionDefinitionNode resource, String httpMethod, + private Optional convertResourceToOperation(FunctionDefinitionNode resourceFunction, String httpMethod, String generateRelativePath, Components components) { OperationInventory operationInventory = new OperationInventory(); operationInventory.setHttpOperation(httpMethod); operationInventory.setPath(generateRelativePath); - /* Set operation id */ - String resName = (resource.functionName().text() + "_" + - generateRelativePath).replaceAll("\\{///}", "_"); - - if (generateRelativePath.equals("/")) { - resName = resource.functionName().text(); - } - operationInventory.setOperationId(getOperationId(resName)); + operationInventory.setOperationId(getOperationId(resourceFunction)); // Set operation summary // Map API documentation - Map apiDocs = listAPIDocumentations(resource, operationInventory); + Map apiDocs = listAPIDocumentations(resourceFunction, operationInventory); //Add path parameters if in path and query parameters - ParameterMapper parameterMapper = new ParameterMapperImpl(resource, operationInventory, components, apiDocs, + ParameterMapper parameterMapper = new ParameterMapperImpl(resourceFunction, operationInventory, components, apiDocs, additionalData, treatNilableAsOptional); parameterMapper.setParameters(); List diagnostics = additionalData.diagnostics(); @@ -207,7 +200,7 @@ private Optional convertResourceToOperation(FunctionDefiniti } } - ResponseMapper responseMapper = new ResponseMapperImpl(resource, operationInventory, components, + ResponseMapper responseMapper = new ResponseMapperImpl(resourceFunction, operationInventory, components, additionalData); responseMapper.setApiResponses(); return Optional.of(operationInventory); diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java index 332a42686..b7d9776d3 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java @@ -64,7 +64,7 @@ public void visit(ServiceDeclarationNode serviceNode) { if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { FunctionDefinitionNode resourceFunction = (FunctionDefinitionNode) child; String resourceMethod = resourceFunction.functionName().text(); - String operationId = generateOperationId(resourceFunction); + String operationId = MapperCommonUtils.getOperationId(resourceFunction); Optional resourceName = getResourceConfigAnnotation(resourceFunction) .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "name")); if (resourceName.isEmpty()) { @@ -77,15 +77,4 @@ public void visit(ServiceDeclarationNode serviceNode) { } } } - - private String generateOperationId(FunctionDefinitionNode resourceFunction) { - String relativePath = MapperCommonUtils.generateRelativePath(resourceFunction); - String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); - String resName = (resourceFunction.functionName().text() + "_" + - cleanResourcePath).replaceAll("\\{///\\}", "_"); - if (cleanResourcePath.equals("/")) { - resName = resourceFunction.functionName().text(); - } - return MapperCommonUtils.getOperationId(resName); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java index 345ab790f..1b146df85 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/utils/MapperCommonUtils.java @@ -123,16 +123,23 @@ public static String generateRelativePath(FunctionDefinitionNode resourceFunctio /** * Generate operationId by removing special characters. * - * @param operationID input function name, record name or operation Id - * @return string with new generated name + * @param resourceFunction resource function definition + * @return string with a unique operationId */ - public static String getOperationId(String operationID) { + public static String getOperationId(FunctionDefinitionNode resourceFunction) { //For the flatten enable we need to remove first Part of valid name check // this - > !operationID.matches("\\b[a-zA-Z][a-zA-Z0-9]*\\b") && - if (operationID.matches("\\b[0-9]*\\b")) { - return operationID; + String relativePath = MapperCommonUtils.generateRelativePath(resourceFunction); + String cleanResourcePath = MapperCommonUtils.unescapeIdentifier(relativePath); + String resName = (resourceFunction.functionName().text() + "_" + + cleanResourcePath).replaceAll("\\{///\\}", "_"); + if (cleanResourcePath.equals("/")) { + resName = resourceFunction.functionName().text(); } - String[] split = operationID.split(Constants.SPECIAL_CHAR_REGEX); + if (resName.matches("\\b[0-9]*\\b")) { + return resName; + } + String[] split = resName.split(Constants.SPECIAL_CHAR_REGEX); StringBuilder validName = new StringBuilder(); for (String part : split) { if (!part.isBlank()) { @@ -143,8 +150,8 @@ public static String getOperationId(String operationID) { validName.append(part); } } - operationID = validName.toString(); - return operationID.substring(0, 1).toLowerCase(Locale.ENGLISH) + operationID.substring(1); + resName = validName.toString(); + return resName.substring(0, 1).toLowerCase(Locale.ENGLISH) + resName.substring(1); } /** From 0a979f2b3d7b557e9defad88cdf97ccb73ba0a79 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Tue, 23 Jan 2024 10:42:47 +0530 Subject: [PATCH 77/85] Fix checkstyle violations caused by line lengths --- .../openapi/service/mapper/ResourceMapperImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java index eaba491ec..529c7930a 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ResourceMapperImpl.java @@ -174,8 +174,8 @@ private void addPathItem(String httpMethod, Paths path, Operation operation, Str * * @return Operation Adaptor object of given resource */ - private Optional convertResourceToOperation(FunctionDefinitionNode resourceFunction, String httpMethod, - String generateRelativePath, + private Optional convertResourceToOperation(FunctionDefinitionNode resourceFunction, + String httpMethod, String generateRelativePath, Components components) { OperationInventory operationInventory = new OperationInventory(); operationInventory.setHttpOperation(httpMethod); @@ -185,8 +185,8 @@ private Optional convertResourceToOperation(FunctionDefiniti // Map API documentation Map apiDocs = listAPIDocumentations(resourceFunction, operationInventory); //Add path parameters if in path and query parameters - ParameterMapper parameterMapper = new ParameterMapperImpl(resourceFunction, operationInventory, components, apiDocs, - additionalData, treatNilableAsOptional); + ParameterMapper parameterMapper = new ParameterMapperImpl(resourceFunction, operationInventory, components, + apiDocs, additionalData, treatNilableAsOptional); parameterMapper.setParameters(); List diagnostics = additionalData.diagnostics(); if (diagnostics.size() > 1 || (diagnostics.size() == 1 && !diagnostics.get(0).getCode().equals( From 4ec420266e7b4600f728d29c473b50748d77e9d9 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Wed, 24 Jan 2024 13:54:56 +0530 Subject: [PATCH 78/85] Remove hateoas meta-data extraction logic from single OAS generation path --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 6e9147959..c28fe7343 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -110,6 +110,7 @@ public static List generateOAS3Definition(Project project, SyntaxTree .setOpenApiFileName(openApiName) .setBallerinaFilePath(inputPath) .setProject(project); + extractHateoasLinkMetadata(project); OASGenerationMetaInfo oasGenerationMetaInfo = builder.build(); OASResult oasDefinition = generateOAS(oasGenerationMetaInfo); oasDefinition.setServiceName(openApiName); @@ -188,7 +189,7 @@ private static void extractServiceNodes(String serviceName, List availab public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) { ServiceDeclarationNode serviceDefinition = oasGenerationMetaInfo.getServiceDeclarationNode(); ModuleMemberVisitor moduleMemberVisitor = extractNodesFromProject(oasGenerationMetaInfo.getProject()); - extractHateoasLinkMetadata(oasGenerationMetaInfo.getProject()); +// extractHateoasLinkMetadata(oasGenerationMetaInfo.getProject()); Set listeners = moduleMemberVisitor.getListenerDeclarationNodes(); SemanticModel semanticModel = oasGenerationMetaInfo.getSemanticModel(); String openApiFileName = oasGenerationMetaInfo.getOpenApiFileName(); From 2cf17b0f9198507b38c2737fe1a49bacf222e4ab Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Wed, 24 Jan 2024 14:58:12 +0530 Subject: [PATCH 79/85] Refactor hateoas-metadata visitor logic --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index c28fe7343..339065077 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -100,6 +100,8 @@ public static List generateOAS3Definition(Project project, SyntaxTree null, serviceName, availableService.toString()); diagnostics.add(error); } + // Extract HATEOAS meta-data for the all the service-declarations in the current project + extractHateoasLinkMetadata(project); // Generating openapi specification for selected services for (Map.Entry serviceNode : servicesToGenerate.entrySet()) { String openApiName = getOpenApiFileName(syntaxTree.filePath(), serviceNode.getKey(), needJson); @@ -110,7 +112,6 @@ public static List generateOAS3Definition(Project project, SyntaxTree .setOpenApiFileName(openApiName) .setBallerinaFilePath(inputPath) .setProject(project); - extractHateoasLinkMetadata(project); OASGenerationMetaInfo oasGenerationMetaInfo = builder.build(); OASResult oasDefinition = generateOAS(oasGenerationMetaInfo); oasDefinition.setServiceName(openApiName); @@ -189,7 +190,6 @@ private static void extractServiceNodes(String serviceName, List availab public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) { ServiceDeclarationNode serviceDefinition = oasGenerationMetaInfo.getServiceDeclarationNode(); ModuleMemberVisitor moduleMemberVisitor = extractNodesFromProject(oasGenerationMetaInfo.getProject()); -// extractHateoasLinkMetadata(oasGenerationMetaInfo.getProject()); Set listeners = moduleMemberVisitor.getListenerDeclarationNodes(); SemanticModel semanticModel = oasGenerationMetaInfo.getSemanticModel(); String openApiFileName = oasGenerationMetaInfo.getOpenApiFileName(); From 90eb48d672af742702eb9b00245208ce99b7c871 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 31 Jan 2024 11:15:20 +0530 Subject: [PATCH 80/85] Remove the visitor usage --- .../mapper/ServiceToOpenAPIMapper.java | 3 +- .../mapper/hateoas/HateoasMapperImpl.java | 94 ++++++++++--------- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 339065077..02cb95a24 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -207,12 +207,11 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) serversMapperImpl.setServers(); // 03. Filter path and component sections in OAS. // Generate openApi string for the mentioned service name. - String packageId = oasGenerationMetaInfo.getProject().currentPackage().packageId().id().toString(); convertServiceToOpenAPI(serviceDefinition, openapi, semanticModel, moduleMemberVisitor, diagnostics); ConstraintMapper constraintMapper = new ConstraintMapperImpl(openapi, moduleMemberVisitor, diagnostics); constraintMapper.setConstraints(); - HateoasMapper hateoasMapper = new HateoasMapperImpl(packageId, semanticModel); + HateoasMapper hateoasMapper = new HateoasMapperImpl(); hateoasMapper.setOpenApiLinks(serviceDefinition, openapi); return new OASResult(openapi, diagnostics); } else { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 438d1b91e..929faf253 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -18,9 +18,6 @@ package io.ballerina.openapi.service.mapper.hateoas; -import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; -import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; @@ -44,7 +41,6 @@ import static io.ballerina.openapi.service.mapper.hateoas.Constants.BALLERINA_LINKEDTO_KEYWORD; import static io.ballerina.openapi.service.mapper.hateoas.Constants.OPENAPI_LINK_DEFAULT_REL; -import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.generateRelativePath; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; @@ -55,23 +51,11 @@ * @since 1.9.0 */ public class HateoasMapperImpl implements HateoasMapper { - private final String packageId; - private final SemanticModel semanticModel; - - public HateoasMapperImpl(String packageId, SemanticModel semanticModel) { - this.packageId = packageId; - this.semanticModel = semanticModel; - } @Override public void setOpenApiLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) { - Optional serviceSymbolOpt = semanticModel.symbol(serviceNode); - if (serviceSymbolOpt.isEmpty()) { - return; - } - ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceSymbolOpt.get(); - int serviceId = serviceSymbol.hashCode(); Paths paths = openAPI.getPaths(); + Service hateoasService = extractHateoasMetaInfo(serviceNode); for (Node node: serviceNode.members()) { if (!node.kind().equals(SyntaxKind.RESOURCE_ACCESSOR_DEFINITION)) { continue; @@ -81,8 +65,28 @@ public void setOpenApiLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) if (responses.isEmpty()) { continue; } - setOpenApiLinksInApiResponse(serviceId, resource, responses.get()); + setOpenApiLinksInApiResponse(hateoasService, resource, responses.get()); + } + } + + private Service extractHateoasMetaInfo(ServiceDeclarationNode serviceNode) { + Service service = new Service("ss", 0); + for (Node child : serviceNode.children()) { + if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { + FunctionDefinitionNode resourceFunction = (FunctionDefinitionNode) child; + String resourceMethod = resourceFunction.functionName().text(); + String operationId = MapperCommonUtils.getOperationId(resourceFunction); + Optional resourceName = getResourceConfigAnnotation(resourceFunction) + .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "name")); + if (resourceName.isEmpty()) { + continue; + } + String cleanedResourceName = resourceName.get().replaceAll("\"", ""); + Resource hateoasResource = new Resource(resourceMethod, operationId); + service.addResource(cleanedResourceName, hateoasResource); + } } + return service; } private Optional getApiResponsesForResource(FunctionDefinitionNode resource, Paths paths) { @@ -120,9 +124,9 @@ private Optional getApiResponsesForResource(FunctionDefinitionNode return Optional.ofNullable(responses); } - private void setOpenApiLinksInApiResponse(int serviceId, FunctionDefinitionNode resource, + private void setOpenApiLinksInApiResponse(Service hateoasService, FunctionDefinitionNode resource, ApiResponses apiResponses) { - Map swaggerLinks = mapHateoasLinksToOpenApiLinks(packageId, serviceId, resource); + Map swaggerLinks = mapHateoasLinksToOpenApiLinks(hateoasService, resource); if (swaggerLinks.isEmpty()) { return; } @@ -134,29 +138,6 @@ private void setOpenApiLinksInApiResponse(int serviceId, FunctionDefinitionNode } } - private Map mapHateoasLinksToOpenApiLinks(String packageId, int serviceId, - FunctionDefinitionNode resourceFunction) { - Optional linkedTo = getResourceConfigAnnotation(resourceFunction) - .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, BALLERINA_LINKEDTO_KEYWORD)); - if (linkedTo.isEmpty()) { - return Collections.emptyMap(); - } - List links = getLinks(linkedTo.get()); - Map hateoasLinks = new HashMap<>(); - for (HateoasLink link : links) { - Optional resource = getHateoasContextHolder() - .getHateoasResource(packageId, serviceId, link.getResourceName(), link.getResourceMethod()); - if (resource.isEmpty()) { - continue; - } - Link openapiLink = new Link(); - String operationId = resource.get().operationId(); - openapiLink.setOperationId(operationId); - hateoasLinks.put(link.getRel(), openapiLink); - } - return hateoasLinks; - } - private List getLinks(String linkedTo) { List links = new ArrayList<>(); String[] linkArray = linkedTo.replaceAll("[\\[\\]]", "").split("\\},\\s*"); @@ -185,4 +166,31 @@ private HateoasLink parseHateoasLink(String input) { hateoasLink.setResourceMethod(keyValueMap.get("method")); return hateoasLink; } + + private Map mapHateoasLinksToOpenApiLinks(Service hateoasService, + FunctionDefinitionNode resourceFunction) { + Optional linkedTo = getResourceConfigAnnotation(resourceFunction) + .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, BALLERINA_LINKEDTO_KEYWORD)); + if (linkedTo.isEmpty()) { + return Collections.emptyMap(); + } + List links = getLinks(linkedTo.get()); + Map hateoasLinks = new HashMap<>(); + for (HateoasLink link : links) { + Optional resource = hateoasService.getHateoasResourceMapping().entrySet().stream() + .filter(resources -> link.getResourceName().equals(resources.getKey())) + .findFirst() + .flatMap(hateoasResourceMapping -> hateoasResourceMapping.getValue().stream() + .filter(hateoasRes -> link.getResourceMethod().equals(hateoasRes.resourceMethod())) + .findFirst()); + if (resource.isEmpty()) { + continue; + } + Link openapiLink = new Link(); + String operationId = resource.get().operationId(); + openapiLink.setOperationId(operationId); + hateoasLinks.put(link.getRel(), openapiLink); + } + return hateoasLinks; + } } From 4c8bdc3e56d26fd80f0fd8fce7c334516cfaa6c7 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 31 Jan 2024 11:23:10 +0530 Subject: [PATCH 81/85] Refactor the code base --- .../mapper/ServiceToOpenAPIMapper.java | 16 ---- .../mapper/hateoas/HateoasContextHolder.java | 76 ------------------ .../mapper/hateoas/HateoasMapperImpl.java | 2 +- .../hateoas/HateoasMetadataVisitor.java | 80 ------------------- .../service/mapper/hateoas/Service.java | 15 ---- 5 files changed, 1 insertion(+), 188 deletions(-) delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 02cb95a24..855203618 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -37,7 +37,6 @@ import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic; import io.ballerina.openapi.service.mapper.hateoas.HateoasMapper; import io.ballerina.openapi.service.mapper.hateoas.HateoasMapperImpl; -import io.ballerina.openapi.service.mapper.hateoas.HateoasMetadataVisitor; import io.ballerina.openapi.service.mapper.model.AdditionalData; import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; @@ -100,8 +99,6 @@ public static List generateOAS3Definition(Project project, SyntaxTree null, serviceName, availableService.toString()); diagnostics.add(error); } - // Extract HATEOAS meta-data for the all the service-declarations in the current project - extractHateoasLinkMetadata(project); // Generating openapi specification for selected services for (Map.Entry serviceNode : servicesToGenerate.entrySet()) { String openApiName = getOpenApiFileName(syntaxTree.filePath(), serviceNode.getKey(), needJson); @@ -273,17 +270,4 @@ private static boolean isTreatNilableAsOptionalParameter(ServiceDeclarationNode } return true; } - - private static void extractHateoasLinkMetadata(Project project) { - String packageId = project.currentPackage().packageId().id().toString(); - project.currentPackage().moduleIds().forEach(moduleId -> { - Module module = project.currentPackage().module(moduleId); - SemanticModel semanticModel = project.currentPackage().getCompilation().getSemanticModel(moduleId); - HateoasMetadataVisitor hateoasMetadataVisitor = new HateoasMetadataVisitor(packageId, semanticModel); - module.documentIds().forEach(documentId -> { - SyntaxTree syntaxTreeDoc = module.document(documentId).syntaxTree(); - syntaxTreeDoc.rootNode().accept(hateoasMetadataVisitor); - }); - }); - } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java deleted file mode 100644 index ee8b66d44..000000000 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasContextHolder.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.ballerina.openapi.service.mapper.hateoas; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -/** - * A context-holder to share HATEOAS meta-data information. - * - * @since 1.9.0 - */ -public final class HateoasContextHolder { - private static HateoasContextHolder instance; - - private final List hateoasServices; - - public HateoasContextHolder() { - this.hateoasServices = new ArrayList<>(); - } - - public static HateoasContextHolder getHateoasContextHolder() { - synchronized (HateoasContextHolder.class) { - if (Objects.isNull(instance)) { - instance = new HateoasContextHolder(); - } - } - return instance; - } - - public void updateHateoasResource(String packageId, int serviceId, String resourceName, Resource resource) { - Optional hateoasService = this.hateoasServices.stream() - .filter(svc -> packageId.equals(svc.getPackageId()) && svc.getServiceId() == serviceId) - .findFirst(); - if (hateoasService.isEmpty()) { - Service service = new Service(packageId, serviceId); - service.addResource(resourceName, resource); - this.hateoasServices.add(service); - return; - } - Service service = hateoasService.get(); - service.addResource(resourceName, resource); - } - - public Optional getHateoasResource(String packageId, int serviceId, String resourceName, - String resourceMethod) { - return this.hateoasServices.stream() - .filter(svc -> svc.getPackageId().equals(packageId) && svc.getServiceId() == serviceId) - .findFirst() - .flatMap(svc -> svc.getHateoasResourceMapping().entrySet().stream() - .filter(resources -> resourceName.equals(resources.getKey())) - .findFirst() - ).flatMap(hateoasResourceMapping -> hateoasResourceMapping.getValue().stream() - .filter(resource -> resourceMethod.equals(resource.resourceMethod())) - .findFirst() - ); - } -} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 929faf253..5436699c4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -70,7 +70,7 @@ public void setOpenApiLinks(ServiceDeclarationNode serviceNode, OpenAPI openAPI) } private Service extractHateoasMetaInfo(ServiceDeclarationNode serviceNode) { - Service service = new Service("ss", 0); + Service service = new Service(); for (Node child : serviceNode.children()) { if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { FunctionDefinitionNode resourceFunction = (FunctionDefinitionNode) child; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java deleted file mode 100644 index b7d9776d3..000000000 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMetadataVisitor.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.ballerina.openapi.service.mapper.hateoas; - -import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; -import io.ballerina.compiler.api.symbols.Symbol; -import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; -import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeVisitor; -import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.compiler.syntax.tree.SyntaxKind; -import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; - -import java.util.Optional; - -import static io.ballerina.openapi.service.mapper.hateoas.HateoasContextHolder.getHateoasContextHolder; -import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getResourceConfigAnnotation; -import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getValueForAnnotationFields; - -/** - * Visitor to retrieve the Hateoas meta-data from resource functions within a {@link ServiceDeclarationNode}. - * - * @since 1.6.0 - */ -public class HateoasMetadataVisitor extends NodeVisitor { - private final String packageId; - private final SemanticModel semanticModel; - - public HateoasMetadataVisitor(String packageId, SemanticModel semanticModel) { - this.packageId = packageId; - this.semanticModel = semanticModel; - } - - @Override - public void visit(ServiceDeclarationNode serviceNode) { - boolean isHttpService = MapperCommonUtils.isHttpService(serviceNode, semanticModel); - if (!isHttpService) { - return; - } - Optional serviceDeclarationOpt = semanticModel.symbol(serviceNode); - if (serviceDeclarationOpt.isEmpty()) { - return; - } - ServiceDeclarationSymbol serviceSymbol = (ServiceDeclarationSymbol) serviceDeclarationOpt.get(); - int serviceId = serviceSymbol.hashCode(); - for (Node child : serviceNode.children()) { - if (SyntaxKind.RESOURCE_ACCESSOR_DEFINITION.equals(child.kind())) { - FunctionDefinitionNode resourceFunction = (FunctionDefinitionNode) child; - String resourceMethod = resourceFunction.functionName().text(); - String operationId = MapperCommonUtils.getOperationId(resourceFunction); - Optional resourceName = getResourceConfigAnnotation(resourceFunction) - .flatMap(resourceConfig -> getValueForAnnotationFields(resourceConfig, "name")); - if (resourceName.isEmpty()) { - return; - } - String cleanedResourceName = resourceName.get().replaceAll("\"", ""); - Resource hateoasResource = new Resource(resourceMethod, operationId); - getHateoasContextHolder().updateHateoasResource( - packageId, serviceId, cleanedResourceName, hateoasResource); - } - } - } -} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index d39960142..19cab76e2 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -29,15 +29,8 @@ * @since 1.6.0 */ public class Service { - private final String packageId; - private final int serviceId; private final Map> hateoasResourceMapping = new HashMap<>(); - public Service(String packageId, int serviceId) { - this.packageId = packageId; - this.serviceId = serviceId; - } - public void addResource(String resourceName, Resource resource) { if (hateoasResourceMapping.containsKey(resourceName)) { hateoasResourceMapping.get(resourceName).add(resource); @@ -46,14 +39,6 @@ public void addResource(String resourceName, Resource resource) { hateoasResourceMapping.put(resourceName, Arrays.asList(resource)); } - public String getPackageId() { - return packageId; - } - - public int getServiceId() { - return serviceId; - } - public Map> getHateoasResourceMapping() { return hateoasResourceMapping; } From e78ea811a6aa5759a1c6e89acc251b6f36932e0b Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Wed, 31 Jan 2024 11:43:21 +0530 Subject: [PATCH 82/85] Update license header Co-authored-by: Sumudu Nissanka --- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 5436699c4..883ca02f4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except From 58d80c2ff9f45fc7abec7153fd97f266e2ae0889 Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Wed, 31 Jan 2024 12:00:35 +0530 Subject: [PATCH 83/85] Update ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java Co-authored-by: Sumudu Nissanka --- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index 92874e5ec..c19e940a3 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except From 58dc4492d6b730aff76fa261e1049853810ec699 Mon Sep 17 00:00:00 2001 From: Sachin Akash Date: Wed, 31 Jan 2024 12:00:49 +0530 Subject: [PATCH 84/85] Update ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java Co-authored-by: Sumudu Nissanka --- .../io/ballerina/openapi/service/mapper/hateoas/Resource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java index c19e940a3..0eb33d695 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Resource.java @@ -22,7 +22,7 @@ * A context-holder to save and retrieve HATEOAS meta-data for a given resources. * @param resourceMethod http resource for the method * @param operationId generated operationId - * @since 1.6.0 + * @since 1.9.0 */ public record Resource(String resourceMethod, String operationId) { } From a2e46df3e601ff3c5e0651a4c9b3edb02197acf7 Mon Sep 17 00:00:00 2001 From: SachinAkash01 Date: Wed, 31 Jan 2024 14:02:41 +0530 Subject: [PATCH 85/85] Update license headers --- .../ballerina/openapi/service/mapper/hateoas/HateoasLink.java | 2 +- .../ballerina/openapi/service/mapper/hateoas/HateoasMapper.java | 2 +- .../openapi/service/mapper/hateoas/HateoasMapperImpl.java | 2 +- .../io/ballerina/openapi/service/mapper/hateoas/Service.java | 2 +- .../openapi/service/mapper/response/ResponseMapper.java | 2 +- .../io/ballerina/openapi/generators/openapi/HateoasTests.java | 2 +- .../ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal | 2 +- .../ballerina-to-openapi/hateoas/hateoas_multiple_links.bal | 2 +- .../resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal | 2 +- .../resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java index d33aa83c4..46e04e16f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasLink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java index b97fec8f1..c31243f55 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java index 5436699c4..883ca02f4 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/HateoasMapperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java index 19cab76e2..11f8ac1b6 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/hateoas/Service.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java index 1673466a9..941e3c315 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/response/ResponseMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java index 0b4c17d15..985cfea8f 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/HateoasTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal index cabd3937f..1609648bd 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_automatic_linking.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal index 1c0ed1493..42c65ae2b 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_multiple_links.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal index e44368ee7..60dc804fd 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/hateoas_self_rel.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal index 9c3831d05..1ad07caaf 100644 --- a/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal +++ b/openapi-cli/src/test/resources/ballerina-to-openapi/hateoas/snowpeak_hateoas.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except