From 21d208ac2a70405e42576ae324c8dd9ef4679e19 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Mon, 15 Jul 2024 08:55:21 +0530 Subject: [PATCH] Refactor service contract implementation with static resource --- .../mapper/ServiceToOpenAPIMapper.java | 61 +++++---- .../mapper/diagnostic/DiagnosticMessages.java | 10 +- .../mapper/model/ModuleMemberVisitor.java | 21 ++++ ...jectType.java => ServiceContractType.java} | 8 +- .../mapper/model/ServiceDeclaration.java | 119 ++++++++++++------ 5 files changed, 154 insertions(+), 65 deletions(-) rename ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/{ServiceObjectType.java => ServiceContractType.java} (96%) 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 912ff64dd..e202bacab 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 @@ -43,10 +43,11 @@ import io.ballerina.openapi.service.mapper.model.ResourceFunction; import io.ballerina.openapi.service.mapper.model.ResourceFunctionDeclaration; import io.ballerina.openapi.service.mapper.model.ResourceFunctionDefinition; +import io.ballerina.openapi.service.mapper.model.ServiceContractType; import io.ballerina.openapi.service.mapper.model.ServiceDeclaration; import io.ballerina.openapi.service.mapper.model.ServiceNode; -import io.ballerina.openapi.service.mapper.model.ServiceObjectType; import io.ballerina.projects.Module; +import io.ballerina.projects.Package; import io.ballerina.projects.Project; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @@ -110,16 +111,8 @@ public static List generateOAS3Definition(Project project, SyntaxTree // Generating openapi specification for selected services for (Map.Entry serviceNode : servicesToGenerate.entrySet()) { String openApiName = getOpenApiFileName(syntaxTree.filePath(), serviceNode.getKey(), needJson); - OASGenerationMetaInfo.OASGenerationMetaInfoBuilder builder = - new OASGenerationMetaInfo.OASGenerationMetaInfoBuilder(); - builder.setServiceNode(serviceNode.getValue()) - .setSemanticModel(semanticModel) - .setOpenApiFileName(openApiName) - .setBallerinaFilePath(inputPath) - .setProject(project); - OASGenerationMetaInfo oasGenerationMetaInfo = builder.build(); - OASResult oasDefinition = generateOAS(oasGenerationMetaInfo); - oasDefinition.setServiceName(openApiName); + OASResult oasDefinition = generateOasFroServiceNode(project, openApiName, + semanticModel, inputPath, serviceNode.getValue()); outputs.add(oasDefinition); } } @@ -130,6 +123,21 @@ public static List generateOAS3Definition(Project project, SyntaxTree return outputs; } + public static OASResult generateOasFroServiceNode(Project project, String openApiName, SemanticModel semanticModel, + Path inputPath, ServiceNode serviceNode) { + OASGenerationMetaInfo.OASGenerationMetaInfoBuilder builder = + new OASGenerationMetaInfo.OASGenerationMetaInfoBuilder(); + builder.setServiceNode(serviceNode) + .setSemanticModel(semanticModel) + .setOpenApiFileName(openApiName) + .setBallerinaFilePath(inputPath) + .setProject(project); + OASGenerationMetaInfo oasGenerationMetaInfo = builder.build(); + OASResult oasDefinition = generateOAS(oasGenerationMetaInfo); + oasDefinition.setServiceName(openApiName); + return oasDefinition; + } + /** * Filter all the end points and service nodes. */ @@ -154,7 +162,7 @@ private static void extractServiceNodes(String serviceName, List availab // TODO: Distinct service types should work here if (descriptorNode.kind().equals(SyntaxKind.OBJECT_TYPE_DESC) && isHttpServiceContract(descriptorNode, semanticModel)) { - ServiceNode service = new ServiceObjectType((TypeDefinitionNode) node); + ServiceNode service = new ServiceContractType((TypeDefinitionNode) node); Optional serviceSymbol = service.getSymbol(semanticModel); serviceSymbol.ifPresent(symbol -> addService(serviceName, availableService, service, servicesToGenerate, symbol)); @@ -169,7 +177,7 @@ public static Optional getServiceNode(Node node, SemanticModel sema } else if (node instanceof TypeDefinitionNode serviceTypeNode && serviceTypeNode.typeDescriptor() instanceof ObjectTypeDescriptorNode serviceNode && isHttpServiceContract(serviceNode, semanticModel)) { - return Optional.of(new ServiceObjectType((TypeDefinitionNode) node)); + return Optional.of(new ServiceContractType((TypeDefinitionNode) node)); } return Optional.empty(); } @@ -222,8 +230,11 @@ private static void addService(String serviceName, List availableService public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) { ServiceNode serviceDefinition = oasGenerationMetaInfo.getServiceNode(); SemanticModel semanticModel = oasGenerationMetaInfo.getSemanticModel(); - ModuleMemberVisitor moduleMemberVisitor = extractNodesFromProject(oasGenerationMetaInfo.getProject()); + Package currentPackage = oasGenerationMetaInfo.getProject().currentPackage(); + ModuleMemberVisitor moduleMemberVisitor = extractNodesFromProject(oasGenerationMetaInfo.getProject(), + semanticModel); Set listeners = moduleMemberVisitor.getListenerDeclarationNodes(); + Set serviceContractTypes = moduleMemberVisitor.getServiceContractTypeNodes(); String openApiFileName = oasGenerationMetaInfo.getOpenApiFileName(); Path ballerinaFilePath = oasGenerationMetaInfo.getBallerinaFilePath(); // 01.Fill the openAPI info section @@ -240,8 +251,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) serversMapperImpl.setServers(); if (oasAvailableViaServiceContract(serviceDefinition)) { - return updateOasResultWithServiceContract((ServiceDeclaration) serviceDefinition, oasResult, - semanticModel); + return updateOasResultWithServiceContract((ServiceDeclaration) serviceDefinition, currentPackage, + oasResult, semanticModel, serviceContractTypes); } convertServiceToOpenAPI(serviceDefinition, serviceMapperFactory); @@ -272,9 +283,11 @@ static boolean oasAvailableViaServiceContract(ServiceNode serviceNode) { ((ServiceDeclaration) serviceNode).implementsServiceContract(); } - private static OASResult updateOasResultWithServiceContract(ServiceDeclaration serviceDeclaration, - OASResult oasResult, SemanticModel semanticModel) { - Optional openAPI = serviceDeclaration.getOpenAPIFromServiceContract(semanticModel); + private static OASResult updateOasResultWithServiceContract(ServiceDeclaration serviceDeclaration, Package pkg, + OASResult oasResult, SemanticModel semanticModel, + Set serviceContractTypes) { + Optional openAPI = serviceDeclaration.getOpenAPIFromServiceContract(pkg, semanticModel, + serviceContractTypes, oasResult.getDiagnostics()); if (openAPI.isEmpty()) { return oasResult; } @@ -287,15 +300,15 @@ private static OASResult updateOasResultWithServiceContract(ServiceDeclaration s // Copy info Info existingOpenAPIInfo = oasResult.getOpenAPI().get().getInfo(); + // Update title + existingOpenAPIInfo.setTitle(openApiFromServiceContract.getInfo().getTitle()); openApiFromServiceContract.setInfo(existingOpenAPIInfo); // Copy servers String basePath = extractBasePath(openApiFromServiceContract); List existingServers = oasResult.getOpenAPI().get().getServers(); existingServers.forEach( - server -> { - server.setUrl(server.getUrl() + basePath); - } + server -> server.setUrl(server.getUrl() + basePath) ); openApiFromServiceContract.setServers(existingServers); oasResult.setOpenAPI(openApiFromServiceContract); @@ -316,8 +329,8 @@ private static String extractBasePath(OpenAPI openApiFromServiceContract) { * * @param project - current project */ - public static ModuleMemberVisitor extractNodesFromProject(Project project) { - ModuleMemberVisitor balNodeVisitor = new ModuleMemberVisitor(); + public static ModuleMemberVisitor extractNodesFromProject(Project project, SemanticModel semanticModel) { + ModuleMemberVisitor balNodeVisitor = new ModuleMemberVisitor(semanticModel); project.currentPackage().moduleIds().forEach(moduleId -> { Module module = project.currentPackage().module(moduleId); module.documentIds().forEach(documentId -> { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java index cc226824a..1eb6e9b4f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java @@ -87,7 +87,15 @@ public enum DiagnosticMessages { OAS_CONVERTOR_126("OAS_CONVERTOR_126", "Generated OpenAPI definition does not contain the response" + "/request parameter information from the interceptor pipeline. Cause: %s", DiagnosticSeverity.WARNING), OAS_CONVERTOR_127("OAS_CONVERTOR_127", "Generated OpenAPI definition does not contain the request" + - " parameter information from the interceptor pipeline. Cause: %s", DiagnosticSeverity.WARNING),; + " parameter information from the interceptor pipeline. Cause: %s", DiagnosticSeverity.WARNING), + OAS_CONVERTOR_128("OAS_CONVERTOR_128", "Generated OpenAPI definition for the service contract type: " + + "'%s' has errors", DiagnosticSeverity.ERROR), + OAS_CONVERTOR_129("OAS_CONVERTOR_129", "Failed to obtain the OpenAPI definition from the service contract" + + " type: '%s'", DiagnosticSeverity.ERROR), + OAS_CONVERTOR_130("OAS_CONVERTOR_130", "Failed to find the package to obtain the OpenAPI definition from the " + + "service contract type: '%s'", DiagnosticSeverity.ERROR), + OAS_CONVERTOR_131("OAS_CONVERTOR_131", "Failed to find the OpenAPI definition resource for the " + + "service contract type: '%s'", DiagnosticSeverity.ERROR); private final String code; private final String description; 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 d0cd2d345..b1016fc33 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 @@ -17,9 +17,12 @@ */ package io.ballerina.openapi.service.mapper.model; +import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.syntax.tree.ClassDefinitionNode; import io.ballerina.compiler.syntax.tree.ListenerDeclarationNode; +import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeVisitor; +import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.compiler.syntax.tree.TypeDefinitionNode; import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils; @@ -27,6 +30,8 @@ import java.util.Optional; import java.util.Set; +import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.isHttpServiceContract; + /** * Visitor to get the TypeDefinitionNode and ListenerDeclarationNodes. * @@ -37,10 +42,22 @@ public class ModuleMemberVisitor extends NodeVisitor { Set typeDefinitionNodes = new LinkedHashSet<>(); Set listenerDeclarationNodes = new LinkedHashSet<>(); Set interceptorServiceClassNodes = new LinkedHashSet<>(); + Set serviceContractTypeNodes = new LinkedHashSet<>(); + SemanticModel semanticModel; + + public ModuleMemberVisitor(SemanticModel semanticModel) { + this.semanticModel = semanticModel; + } @Override public void visit(TypeDefinitionNode typeDefinitionNode) { typeDefinitionNodes.add(typeDefinitionNode); + Node descriptorNode = typeDefinitionNode.typeDescriptor(); + // TODO: Distinct service types should work here + if (descriptorNode.kind().equals(SyntaxKind.OBJECT_TYPE_DESC) && + isHttpServiceContract(descriptorNode, semanticModel)) { + serviceContractTypeNodes.add(new ServiceContractType(typeDefinitionNode)); + } } @Override @@ -74,4 +91,8 @@ public Optional getInterceptorServiceClassNode(String typeN } return Optional.empty(); } + + public Set getServiceContractTypeNodes() { + return serviceContractTypeNodes; + } } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceObjectType.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceContractType.java similarity index 96% rename from ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceObjectType.java rename to ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceContractType.java index 25a41c161..d588f2469 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceObjectType.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceContractType.java @@ -27,14 +27,14 @@ import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createSeparatedNodeList; import static io.ballerina.compiler.syntax.tree.NodeFactory.createMetadataNode; -public class ServiceObjectType implements ServiceNode { +public class ServiceContractType implements ServiceNode { private static final String DEFAULT_PATH = "/"; ObjectTypeDescriptorNode serviceObjType; TypeDefinitionNode serviceTypeDefinition; int serviceId; - public ServiceObjectType(TypeDefinitionNode serviceType) { + public ServiceContractType(TypeDefinitionNode serviceType) { serviceId = serviceType.hashCode(); serviceTypeDefinition = new TypeDefinitionNode(serviceType.internalNode(), serviceType.position(), serviceType.parent()); @@ -43,6 +43,10 @@ public ServiceObjectType(TypeDefinitionNode serviceType) { serviceObjTypeDesc.parent()); } + public boolean matchesName(String name) { + return serviceTypeDefinition.typeName().text().equals(name); + } + public Optional metadata() { return serviceTypeDefinition.metadata(); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java index 9781c1e90..36e852f31 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java @@ -1,15 +1,14 @@ package io.ballerina.openapi.service.mapper.model; +import io.ballerina.compiler.api.ModuleID; import io.ballerina.compiler.api.SemanticModel; -import io.ballerina.compiler.api.symbols.Annotatable; -import io.ballerina.compiler.api.symbols.AnnotationAttachmentSymbol; import io.ballerina.compiler.api.symbols.MethodSymbol; +import io.ballerina.compiler.api.symbols.ModuleSymbol; import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; -import io.ballerina.compiler.api.values.ConstantValue; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.ExpressionNode; import io.ballerina.compiler.syntax.tree.MetadataNode; @@ -19,7 +18,16 @@ import io.ballerina.compiler.syntax.tree.SeparatedNodeList; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; import io.ballerina.compiler.syntax.tree.TypeDescriptorNode; +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.utils.MapperCommonUtils; +import io.ballerina.projects.DocumentId; +import io.ballerina.projects.Module; +import io.ballerina.projects.Package; +import io.ballerina.projects.PackageDescriptor; +import io.ballerina.projects.ResolvedPackageDependency; +import io.ballerina.tools.diagnostics.DiagnosticSeverity; import io.ballerina.tools.diagnostics.Location; import io.swagger.parser.OpenAPIParser; import io.swagger.v3.oas.models.OpenAPI; @@ -27,24 +35,23 @@ import io.swagger.v3.parser.core.models.SwaggerParseResult; import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.HashMap; +import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import static io.ballerina.compiler.syntax.tree.NodeFactory.createMetadataNode; import static io.ballerina.openapi.service.mapper.Constants.BALLERINA; import static io.ballerina.openapi.service.mapper.Constants.EMPTY; import static io.ballerina.openapi.service.mapper.Constants.HTTP; import static io.ballerina.openapi.service.mapper.Constants.HTTP_SERVICE_CONTRACT; -import static io.ballerina.openapi.service.mapper.Constants.HTTP_SERVICE_CONTRACT_INFO; -import static io.ballerina.openapi.service.mapper.Constants.OPENAPI_DEFINITION; +import static io.ballerina.openapi.service.mapper.ServiceToOpenAPIMapper.generateOasFroServiceNode; public class ServiceDeclaration implements ServiceNode { ServiceDeclarationNode serviceDeclarationNode; int serviceId; - TypeSymbol serviceContractType; + TypeReferenceTypeSymbol serviceContractType; public ServiceDeclaration(ServiceDeclarationNode serviceNode, SemanticModel semanticModel) { serviceId = serviceNode.hashCode(); @@ -53,15 +60,15 @@ public ServiceDeclaration(ServiceDeclarationNode serviceNode, SemanticModel sema serviceContractType = extractServiceContractType(serviceNode, semanticModel); } - private static TypeSymbol extractServiceContractType(ServiceDeclarationNode serviceNode, - SemanticModel semanticModel) { + private static TypeReferenceTypeSymbol extractServiceContractType(ServiceDeclarationNode serviceNode, + SemanticModel semanticModel) { Optional typeDescriptorNode = serviceNode.typeDescriptor(); if (typeDescriptorNode.isEmpty()) { return null; } Optional symbol = semanticModel.symbol(typeDescriptorNode.get()); - if (symbol.isEmpty() || !(symbol.get() instanceof TypeSymbol typeSymbol)) { + if (symbol.isEmpty() || !(symbol.get() instanceof TypeReferenceTypeSymbol typeSymbol)) { return null; } @@ -152,59 +159,95 @@ public boolean implementsServiceContract() { return Objects.nonNull(serviceContractType); } - public Optional getOpenAPIFromServiceContract(SemanticModel semanticModel) { - Optional encodedOpenAPISpec = getEncodedOpenAPISpec(semanticModel); - if (encodedOpenAPISpec.isEmpty()) { + public Optional getOpenAPIFromServiceContract(Package pkg, SemanticModel semanticModel, + Set serviceContractTypes, + List diagnostics) { + Optional jsonOpenApi = getOpenAPISpecFromResources(pkg, semanticModel, serviceContractTypes, + diagnostics); + if (jsonOpenApi.isEmpty()) { return Optional.empty(); } - byte[] openAPISpec = Base64.getDecoder().decode(encodedOpenAPISpec.get()); - String jsonOpenAPIString = new String(openAPISpec, StandardCharsets.UTF_8); ParseOptions parseOptions = new ParseOptions(); parseOptions.setResolve(true); parseOptions.setFlatten(true); - SwaggerParseResult parseResult = new OpenAPIParser().readContents(jsonOpenAPIString, null, parseOptions); + SwaggerParseResult parseResult = new OpenAPIParser().readContents(jsonOpenApi.get(), null, parseOptions); return Optional.of(parseResult.getOpenAPI()); } - private Optional getEncodedOpenAPISpec(SemanticModel semanticModel) { - if (Objects.isNull(serviceContractType) || - !(serviceContractType instanceof TypeReferenceTypeSymbol serviceContractTypeRef)) { + private Optional getOpenAPISpecFromResources(Package pkg, SemanticModel semanticModel, + Set serviceContractTypes, + List diagnostics) { + Optional serviceName = serviceContractType.getName(); + if (serviceName.isEmpty()) { return Optional.empty(); } - if (!(serviceContractTypeRef.definition() instanceof Annotatable annotatableServiceContractType)) { + String openApiFileName = serviceName.get() + ".json"; + + Optional serviceContractModule = serviceContractType.getModule(); + if (serviceContractModule.isEmpty()) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_129, serviceName.get())); return Optional.empty(); } + ModuleID serviceContractModuleId = serviceContractModule.get().id(); - Optional serviceContractInfoSymbol = semanticModel.types().getTypeByName(BALLERINA, HTTP, EMPTY, - HTTP_SERVICE_CONTRACT_INFO); - if (serviceContractInfoSymbol.isEmpty() || - !(serviceContractInfoSymbol.get() instanceof TypeDefinitionSymbol serviceContractInfoType)) { + Optional serviceSymbol = semanticModel.symbol(serviceDeclarationNode); + if (serviceSymbol.isEmpty()) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_129, serviceName.get())); return Optional.empty(); } - Optional serviceContractInfo = annotatableServiceContractType.annotAttachments() - .stream() - .filter(annotAttachment -> annotAttachment.typeDescriptor().typeDescriptor().isPresent() && - annotAttachment.typeDescriptor().typeDescriptor().get().subtypeOf( - serviceContractInfoType.typeDescriptor())) - .findFirst(); - if (serviceContractInfo.isEmpty()) { + Optional currentModule = serviceSymbol.get().getModule(); + if (currentModule.isEmpty()) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_129, serviceName.get())); return Optional.empty(); } + ModuleID currentModuleId = currentModule.get().id(); + + if (currentModuleId.orgName().equals(serviceContractModuleId.orgName()) && currentModuleId.moduleName() + .equals(serviceContractModuleId.moduleName())) { + Optional serviceContract = serviceContractTypes.stream() + .filter(contractType -> contractType.matchesName(serviceName.get())) + .findFirst(); + if (serviceContract.isEmpty()) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_129, serviceName.get())); + return Optional.empty(); + } + OASResult oasResult = generateOasFroServiceNode(pkg.project(), serviceName.get(), semanticModel, null, + serviceContract.get()); + if (oasResult.getDiagnostics().stream() + .anyMatch(diagnostic -> diagnostic.getDiagnosticSeverity().equals(DiagnosticSeverity.ERROR))) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_128, serviceName.get())); + return Optional.empty(); + } + return oasResult.getJson(); + } - Optional annotationValue = serviceContractInfo.get().attachmentValue(); - if (annotationValue.isEmpty() || !(annotationValue.get().value() instanceof HashMap annotationValueMap)) { + Optional resolvedPackage = pkg.getResolution().allDependencies().stream() + .filter(dependency -> { + PackageDescriptor descriptor = dependency.packageInstance().descriptor(); + return descriptor.org().value().equals(serviceContractModuleId.orgName()) && + descriptor.name().value().equals(serviceContractModuleId.packageName()); + }) + .findFirst(); + if (resolvedPackage.isEmpty()) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_130, String.format("%s/%s:%s", + serviceContractModuleId.orgName(), serviceContractModuleId.packageName(), serviceName.get()))); return Optional.empty(); } - Object openAPIDef = annotationValueMap.get(OPENAPI_DEFINITION); - if (Objects.isNull(openAPIDef) || !(openAPIDef instanceof ConstantValue openAPIDefValue)) { + Module defaultModule = resolvedPackage.get().packageInstance().getDefaultModule(); + Optional openApiDocument = defaultModule.resourceIds().stream() + .filter(resourceId -> resourceId.toString().contains(openApiFileName)) + .findFirst(); + if (openApiDocument.isEmpty()) { + diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_131, String.format("%s/%s:%s", + serviceContractModuleId.orgName(), serviceContractModuleId.packageName(), serviceName.get()))); return Optional.empty(); } - return openAPIDefValue.value() instanceof String openAPIDefString ? - Optional.of(openAPIDefString) : Optional.empty(); + byte[] openApiContent = defaultModule.resource(openApiDocument.get()).content(); + return Optional.of(new String(openApiContent, StandardCharsets.UTF_8)); } }