From 0d8e71ff42a45e653617d2e80a13f20f119a3ebb Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Wed, 4 Sep 2024 14:28:42 +0530 Subject: [PATCH 01/13] [Automated] Update the toml files for client native tests --- openapi-client-native/ballerina-tests/Dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi-client-native/ballerina-tests/Dependencies.toml b/openapi-client-native/ballerina-tests/Dependencies.toml index a0742b639..125afab60 100644 --- a/openapi-client-native/ballerina-tests/Dependencies.toml +++ b/openapi-client-native/ballerina-tests/Dependencies.toml @@ -5,7 +5,7 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.10.0-20240806-083400-aabac46a" +distribution-version = "2201.10.0" [[package]] org = "ballerina" From b616a35a4d712b768c1fb165318adbb58d8b88a3 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 09:47:52 +0530 Subject: [PATCH 02/13] Sanitize the auto generated names --- ...aClientGeneratorWithStatusCodeBinding.java | 4 +-- .../client/FunctionBodyGeneratorImp.java | 19 ++++++----- .../client/ImplFunctionBodyGenerator.java | 5 +-- .../ImplFunctionSignatureGenerator.java | 4 +++ .../RemoteExternalFunctionGenerator.java | 3 +- .../client/RemoteFunctionGenerator.java | 8 +++-- .../RemoteFunctionSignatureGenerator.java | 34 ++++++++++++++++--- .../ResourceExternalFunctionGenerator.java | 3 +- .../client/ResourceFunctionGenerator.java | 8 +++-- .../ResourceFunctionSignatureGenerator.java | 34 ++++++++++++++++--- .../parameter/HeadersParameterGenerator.java | 34 +++++++++++++++++-- .../generators/common/GeneratorUtils.java | 5 ++- .../core/generators/common/OASModifier.java | 3 +- 13 files changed, 127 insertions(+), 37 deletions(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGeneratorWithStatusCodeBinding.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGeneratorWithStatusCodeBinding.java index b8d9da4b7..e9a275526 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGeneratorWithStatusCodeBinding.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/BallerinaClientGeneratorWithStatusCodeBinding.java @@ -257,8 +257,8 @@ protected FunctionBodyGenerator getFunctionBodyGeneratorImp(String path, ImplFunctionSignatureGenerator signatureGenerator) { return new ImplFunctionBodyGenerator(path, operation, openAPI, authConfigGeneratorImp, ballerinaUtilGenerator, imports, signatureGenerator.hasHeaders(), - signatureGenerator.hasDefaultHeaders(), signatureGenerator.hasQueries(), hasDefaultResponse, - nonDefaultStatusCodes); + signatureGenerator.hasDefaultHeaders(), signatureGenerator.hasQueries(), + signatureGenerator.getHeadersParamName(), hasDefaultResponse, nonDefaultStatusCodes); } /** diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/FunctionBodyGeneratorImp.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/FunctionBodyGeneratorImp.java index 1a1854717..4030803e2 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/FunctionBodyGeneratorImp.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/FunctionBodyGeneratorImp.java @@ -100,7 +100,6 @@ import static io.ballerina.openapi.core.generators.common.GeneratorConstants.DELETE; import static io.ballerina.openapi.core.generators.common.GeneratorConstants.ENCODING; import static io.ballerina.openapi.core.generators.common.GeneratorConstants.EXECUTE; -import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADER_VALUES; import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HTTP_HEADERS; import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HTTP_REQUEST; @@ -136,6 +135,7 @@ public class FunctionBodyGeneratorImp implements FunctionBodyGenerator { private final OpenAPI openAPI; private final BallerinaUtilGenerator ballerinaUtilGenerator; private final AuthConfigGeneratorImp ballerinaAuthConfigGeneratorImp; + private String headersParamName; private final boolean hasHeaders; private final boolean hasQueries; @@ -150,7 +150,7 @@ public FunctionBodyGeneratorImp(String path, Map.Entry imports, boolean hasHeaders, - boolean hasDefaultHeaders, boolean hasQueries) { + boolean hasDefaultHeaders, boolean hasQueries, String headersParamName) { this.path = path; this.operation = operation; this.openAPI = openAPI; @@ -160,6 +160,7 @@ public FunctionBodyGeneratorImp(String path, Map.Entry queryParameters, List queryParameters, List statementsList, List statementsList, Str if (method.equals(POST) || method.equals(PUT) || method.equals(PATCH) || method.equals(DELETE) || method.equals(EXECUTE)) { requestStatement = getClientCallWithRequestAndHeaders().formatted(method, RESOURCE_PATH, - hasDefaultHeaders ? HEADERS : HTTP_HEADERS); + hasDefaultHeaders ? headersParamName : HTTP_HEADERS); generateReturnStatement(statementsList, requestStatement); } } else { diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionBodyGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionBodyGenerator.java index 70d66ef01..723e3339b 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionBodyGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionBodyGenerator.java @@ -42,10 +42,11 @@ public ImplFunctionBodyGenerator(String path, Map.Entry imports, boolean hasHeaders, - boolean hasDefaultHeaders, boolean hasQueries, boolean hasDefaultResponse, + boolean hasDefaultHeaders, boolean hasQueries, String headersParamName, + boolean hasDefaultResponse, List nonDefaultStatusCodes) { super(path, operation, openAPI, ballerinaAuthConfigGeneratorImp, ballerinaUtilGenerator, imports, - hasHeaders, hasDefaultHeaders, hasQueries); + hasHeaders, hasDefaultHeaders, hasQueries, headersParamName); this.hasDefaultStatusResponse = hasDefaultResponse; this.nonDefaultStatusCodes = nonDefaultStatusCodes; } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionSignatureGenerator.java index 3816d1c5e..a1dbf88fc 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ImplFunctionSignatureGenerator.java @@ -138,4 +138,8 @@ public boolean hasHeaders() { public boolean hasQueries() { return resourceFunctionSignatureGenerator.hasQueries(); } + + public String getHeadersParamName() { + return resourceFunctionSignatureGenerator.getHeadersParamName(); + } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteExternalFunctionGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteExternalFunctionGenerator.java index 76f9a7080..92f64830f 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteExternalFunctionGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteExternalFunctionGenerator.java @@ -112,7 +112,8 @@ qualifierList, functionKeyWord, functionName, createEmptyNodeList(), functionSig @Override protected Optional getFunctionBodyNode(List diagnostics, boolean hasHeaders, - boolean hasDefaultHeaders, boolean hasQueries) { + boolean hasDefaultHeaders, boolean hasQueries, + String headersParamName) { QualifiedNameReferenceNode javaMethodToken = createQualifiedNameReferenceNode( createIdentifierToken("java"), createToken(COLON_TOKEN), createIdentifierToken("Method")); BasicLiteralNode classValueExp = createBasicLiteralNode(STRING_LITERAL, diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionGenerator.java index cd4c8c706..206f04d15 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionGenerator.java @@ -74,7 +74,7 @@ public Optional generateFunction() { //Create function body Optional functionBodyNodeResult = getFunctionBodyNode(diagnostics, signatureGenerator.hasHeaders(), signatureGenerator.hasDefaultHeaders(), - signatureGenerator.hasQueries()); + signatureGenerator.hasQueries(), signatureGenerator.getHeadersParamName()); if (functionBodyNodeResult.isEmpty()) { return Optional.empty(); } @@ -85,9 +85,11 @@ public Optional generateFunction() { } protected Optional getFunctionBodyNode(List diagnostics, boolean hasHeaders, - boolean hasDefaultHeaders, boolean hasQueries) { + boolean hasDefaultHeaders, boolean hasQueries, + String headersParamName) { FunctionBodyGeneratorImp functionBodyGenerator = new FunctionBodyGeneratorImp(path, operation, openAPI, - authConfigGeneratorImp, ballerinaUtilGenerator, imports, hasHeaders, hasDefaultHeaders, hasQueries); + authConfigGeneratorImp, ballerinaUtilGenerator, imports, hasHeaders, hasDefaultHeaders, hasQueries, + headersParamName); Optional functionBodyNodeResult = functionBodyGenerator.getFunctionBodyNode(); if (functionBodyNodeResult.isEmpty()) { diagnostics.addAll(functionBodyGenerator.getDiagnostics()); diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java index e0ad50756..7ce31c46d 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java @@ -18,6 +18,7 @@ package io.ballerina.openapi.core.generators.client; +import io.ballerina.compiler.syntax.tree.DefaultableParameterNode; import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeFactory; @@ -47,6 +48,7 @@ import static io.ballerina.compiler.syntax.tree.SyntaxKind.COMMA_TOKEN; import static io.ballerina.compiler.syntax.tree.SyntaxKind.OPEN_PAREN_TOKEN; import static io.ballerina.openapi.core.generators.client.diagnostic.DiagnosticMessages.OAS_CLIENT_100; +import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; import static io.ballerina.openapi.core.generators.common.GeneratorUtils.extractReferenceType; public class RemoteFunctionSignatureGenerator implements FunctionSignatureGenerator { @@ -56,6 +58,7 @@ public class RemoteFunctionSignatureGenerator implements FunctionSignatureGenera FunctionReturnTypeGeneratorImp functionReturnTypeGenerator; private final String httpMethod; private final String path; + private String headersParamName = HEADERS; private boolean hasDefaultHeader = false; private boolean hasHeadersParam = false; @@ -125,6 +128,7 @@ protected ParametersInfo getParametersInfo(List parameters) { List headerParameters = new ArrayList<>(); List queryParameters = new ArrayList<>(); + List pathParameters = new ArrayList<>(); // 1. path parameters if (parameters != null) { @@ -159,14 +163,17 @@ protected ParametersInfo getParametersInfo(List parameters) { // 2. parameters - query, headers if (parameters != null) { - populateQueryAndHeaderParameters(parameters, queryParameters, headerParameters); + populateQueryAndHeaderParameters(parameters, queryParameters, headerParameters, pathParameters); + List nonHeaderParameters = new ArrayList<>(queryParameters) {{ + addAll(pathParameters); + }}; HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, - openAPI, operation, httpMethod, path); + openAPI, operation, httpMethod, path, nonHeaderParameters); Optional headers; if (headerParameters.isEmpty()) { hasDefaultHeader = true; - headers = HeadersParameterGenerator.getDefaultParameterNode(); + headers = HeadersParameterGenerator.getDefaultParameterNode(nonHeaderParameters); } else { headers = headersParameterGenerator.generateParameterNode(); } @@ -177,6 +184,7 @@ protected ParametersInfo getParametersInfo(List parameters) { } if (headers.isPresent()) { + populateHeadersParamName(headers.get()); hasHeadersParam = true; if (headers.get() instanceof RequiredParameterNode headerNode) { requiredParams.add(headerNode); @@ -207,6 +215,7 @@ protected ParametersInfo getParametersInfo(List parameters) { } else { ParameterNode defaultHeaderParam = HeadersParameterGenerator.getDefaultParameterNode().orElse(null); if (defaultHeaderParam != null) { + populateHeadersParamName(defaultHeaderParam); hasDefaultHeader = true; hasHeadersParam = true; defaultableParams.add(defaultHeaderParam); @@ -216,8 +225,18 @@ protected ParametersInfo getParametersInfo(List parameters) { return new ParametersInfo(requiredParams, defaultableParams, includedParam); } + private void populateHeadersParamName(ParameterNode parameterNode) { + if (parameterNode instanceof RequiredParameterNode requiredParameterNode && + requiredParameterNode.paramName().isPresent()) { + headersParamName = requiredParameterNode.paramName().get().text(); + } else if (parameterNode instanceof DefaultableParameterNode parameter && + parameter.paramName().isPresent()) { + headersParamName = parameter.paramName().get().text(); + } + } + private void populateQueryAndHeaderParameters(List parameters, List queryParameters, - List headerParameters) { + List headerParameters, List pathParameters) { for (Parameter parameter : parameters) { if (parameter.get$ref() != null) { String paramType = null; @@ -240,6 +259,9 @@ private void populateQueryAndHeaderParameters(List parameters, List

getNonDefaultStatusCodes() { return functionReturnTypeGenerator.getNonDefaultStatusCodes(); } + + public String getHeadersParamName() { + return headersParamName; + } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceExternalFunctionGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceExternalFunctionGenerator.java index b2b269ace..e7bfa80f8 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceExternalFunctionGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceExternalFunctionGenerator.java @@ -112,7 +112,8 @@ protected Optional getFunctionDefinitionNode(NodeList getFunctionBodyNode(List diagnostics, boolean hasHeaders, - boolean hasDefaultHeaders, boolean hasQueries) { + boolean hasDefaultHeaders, boolean hasQueries, + String headersParamName) { QualifiedNameReferenceNode javaMethodToken = createQualifiedNameReferenceNode( createIdentifierToken("java"), createToken(COLON_TOKEN), createIdentifierToken("Method")); BasicLiteralNode classValueExp = createBasicLiteralNode(STRING_LITERAL, diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionGenerator.java index 163525d6d..72b525926 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionGenerator.java @@ -93,7 +93,7 @@ public Optional generateFunction() { //Create function body Optional functionBodyNodeResult = getFunctionBodyNode(diagnostics, signatureGenerator.hasHeaders(), signatureGenerator.hasDefaultHeaders(), - signatureGenerator.hasQueries()); + signatureGenerator.hasQueries(), signatureGenerator.getHeadersParamName()); if (functionBodyNodeResult.isEmpty()) { return Optional.empty(); } @@ -105,9 +105,11 @@ public Optional generateFunction() { } protected Optional getFunctionBodyNode(List diagnostics, boolean hasHeaders, - boolean hasDefaultHeaders, boolean hasQueries) { + boolean hasDefaultHeaders, boolean hasQueries, + String headersParamName) { FunctionBodyGeneratorImp functionBodyGenerator = new FunctionBodyGeneratorImp(path, operation, openAPI, - authConfigGeneratorImp, ballerinaUtilGenerator, imports, hasHeaders, hasDefaultHeaders, hasQueries); + authConfigGeneratorImp, ballerinaUtilGenerator, imports, hasHeaders, hasDefaultHeaders, hasQueries, + headersParamName); Optional functionBodyNodeResult = functionBodyGenerator.getFunctionBodyNode(); if (functionBodyNodeResult.isEmpty()) { diagnostics.addAll(functionBodyGenerator.getDiagnostics()); diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java index a4c5bbae9..782b8df57 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java @@ -18,6 +18,7 @@ package io.ballerina.openapi.core.generators.client; +import io.ballerina.compiler.syntax.tree.DefaultableParameterNode; import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeFactory; @@ -46,6 +47,7 @@ import static io.ballerina.compiler.syntax.tree.SyntaxKind.COMMA_TOKEN; import static io.ballerina.compiler.syntax.tree.SyntaxKind.OPEN_PAREN_TOKEN; import static io.ballerina.openapi.core.generators.client.diagnostic.DiagnosticMessages.OAS_CLIENT_100; +import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; import static io.ballerina.openapi.core.generators.common.GeneratorUtils.extractReferenceType; public class ResourceFunctionSignatureGenerator implements FunctionSignatureGenerator { @@ -55,6 +57,7 @@ public class ResourceFunctionSignatureGenerator implements FunctionSignatureGene protected FunctionReturnTypeGeneratorImp functionReturnTypeGenerator; private final String httpMethod; private final String path; + private String headersParamName = HEADERS; private boolean hasDefaultHeader = false; private boolean hasHeadersParam = false; @@ -125,6 +128,7 @@ protected ParametersInfo getParametersInfo(List parameters) { List headerParameters = new ArrayList<>(); List queryParameters = new ArrayList<>(); + List pathParameters = new ArrayList<>(); // 1. requestBody if (operation.getRequestBody() != null) { @@ -142,14 +146,17 @@ protected ParametersInfo getParametersInfo(List parameters) { // 2. parameters - query, requestBody, headers if (parameters != null) { - populateHeaderAndQueryParameters(parameters, queryParameters, headerParameters); + populateHeaderAndQueryParameters(parameters, queryParameters, headerParameters, pathParameters); + List nonHeaderParameters = new ArrayList<>(queryParameters) {{ + addAll(pathParameters); + }}; HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, - openAPI, operation, httpMethod, path); + openAPI, operation, httpMethod, path, nonHeaderParameters); Optional headers; if (headerParameters.isEmpty()) { hasDefaultHeader = true; - headers = HeadersParameterGenerator.getDefaultParameterNode(); + headers = HeadersParameterGenerator.getDefaultParameterNode(nonHeaderParameters); } else { headers = headersParameterGenerator.generateParameterNode(); } @@ -160,6 +167,7 @@ protected ParametersInfo getParametersInfo(List parameters) { } if (headers.isPresent()) { + populateHeadersParamName(headers.get()); hasHeadersParam = true; if (headers.get() instanceof RequiredParameterNode headerNode) { requiredParams.add(headerNode); @@ -190,6 +198,7 @@ protected ParametersInfo getParametersInfo(List parameters) { } else { ParameterNode defaultHeaderParam = HeadersParameterGenerator.getDefaultParameterNode().orElse(null); if (defaultHeaderParam != null) { + populateHeadersParamName(defaultHeaderParam); hasDefaultHeader = true; hasHeadersParam = true; defaultableParams.add(defaultHeaderParam); @@ -200,8 +209,18 @@ protected ParametersInfo getParametersInfo(List parameters) { return new ParametersInfo(requiredParams, defaultableParams, includedParam); } + private void populateHeadersParamName(ParameterNode parameterNode) { + if (parameterNode instanceof RequiredParameterNode requiredParameterNode && + requiredParameterNode.paramName().isPresent()) { + headersParamName = requiredParameterNode.paramName().get().text(); + } else if (parameterNode instanceof DefaultableParameterNode parameter && + parameter.paramName().isPresent()) { + headersParamName = parameter.paramName().get().text(); + } + } + private void populateHeaderAndQueryParameters(List parameters, List queryParameters, - List headerParameters) { + List headerParameters, List pathParameters) { for (Parameter parameter : parameters) { if (parameter.get$ref() != null) { String paramType = null; @@ -224,6 +243,9 @@ private void populateHeaderAndQueryParameters(List parameters, List

getNonDefaultStatusCodes() { return functionReturnTypeGenerator.getNonDefaultStatusCodes(); } + + public String getHeadersParamName() { + return headersParamName; + } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java index 1c2e7ac7f..27355d889 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java @@ -56,6 +56,7 @@ public class HeadersParameterGenerator implements ParameterGenerator { private final String httpMethod; private final String path; private boolean hasErrors = false; + private final List otherParamNames; public HeadersParameterGenerator(List parameters, OpenAPI openAPI, Operation operation, String httpMethod, String path) { @@ -64,6 +65,17 @@ public HeadersParameterGenerator(List parameters, OpenAPI openAPI, Op this.operation = operation; this.httpMethod = httpMethod; this.path = path; + this.otherParamNames = new ArrayList<>(); + } + + public HeadersParameterGenerator(List parameters, OpenAPI openAPI, Operation operation, + String httpMethod, String path, List otherParameters) { + this.parameters = parameters; + this.openAPI = openAPI; + this.operation = operation; + this.httpMethod = httpMethod; + this.path = path; + this.otherParamNames = otherParameters.stream().map(Parameter::getName).toList(); } @Override @@ -111,14 +123,30 @@ private ParameterNode createParameterNode(TypeDescriptorNode headersType, boolea createEmptyMinutiaeList()); BasicLiteralNode defaultMapExp = createBasicLiteralNode(null, defaultMapVal); return createDefaultableParameterNode(createEmptyNodeList(), headersType, - createIdentifierToken(HEADERS), createToken(EQUAL_TOKEN), defaultMapExp); + createIdentifierToken(getHeadersParamName(otherParamNames)), createToken(EQUAL_TOKEN), + defaultMapExp); } else { return createRequiredParameterNode(createEmptyNodeList(), headersType, - createIdentifierToken(HEADERS)); + createIdentifierToken(getHeadersParamName(otherParamNames))); + } + } + + public static String getHeadersParamName(List otherParamNames) { + String headersParamName = HEADERS; + int i = 1; + while (otherParamNames.contains(headersParamName)) { + headersParamName = HEADERS + i; + i++; } + return headersParamName; } public static Optional getDefaultParameterNode() { + return getDefaultParameterNode(new ArrayList<>()); + } + + public static Optional getDefaultParameterNode(List otherParameters) { + List otherParamNames = otherParameters.stream().map(Parameter::getName).toList(); TypeDescriptorNode stringType = createSimpleNameReferenceNode( createIdentifierToken(GeneratorConstants.STRING)); @@ -138,7 +166,7 @@ public static Optional getDefaultParameterNode() { createEmptyMinutiaeList()); BasicLiteralNode defaultMapExp = createBasicLiteralNode(null, defaultMapVal); return Optional.of(createDefaultableParameterNode(createEmptyNodeList(), defaultHeadersType, - createIdentifierToken(HEADERS), createToken(EQUAL_TOKEN), defaultMapExp)); + createIdentifierToken(getHeadersParamName(otherParamNames)), createToken(EQUAL_TOKEN), defaultMapExp)); } @Override diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java index 66391972c..4a875013d 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java @@ -403,13 +403,12 @@ public static String getValidName(String identifier, boolean isSchema) { //For the flatten enable we need to remove first Part of valid name check // this - > !identifier.matches("\\b[a-zA-Z][a-zA-Z0-9]*\\b") && if (!identifier.matches("\\b[0-9]*\\b")) { - String[] split = identifier.split(GeneratorConstants.ESCAPE_PATTERN); + String[] split = identifier.split(GeneratorConstants.ESCAPE_PATTERN_FOR_MODIFIER); StringBuilder validName = new StringBuilder(); for (String part : split) { if (!part.isBlank()) { if (split.length > 1) { - part = part.substring(0, 1).toUpperCase(Locale.ENGLISH) + - part.substring(1).toLowerCase(Locale.ENGLISH); + part = part.substring(0, 1).toUpperCase(Locale.ENGLISH) + part.substring(1); } validName.append(part); } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java index d4ad288f7..2680a46b0 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java @@ -398,8 +398,7 @@ public static String getValidNameForParameter(String identifier) { StringBuilder validName = new StringBuilder(); for (String part : split) { if (!part.isBlank()) { - part = part.substring(0, 1).toUpperCase(Locale.ENGLISH) + - part.substring(1).toLowerCase(Locale.ENGLISH); + part = part.substring(0, 1).toUpperCase(Locale.ENGLISH) + part.substring(1); validName.append(part); } } From 2c847a4787474cb3e9009291c93a9fd3389ac129 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 09:48:03 +0530 Subject: [PATCH 03/13] Fix test cases --- .../client/FunctionBodyNodeTests.java | 3 +- .../RemoteFunctionNameValidationTests.java | 2 +- .../expected_gen/jira_openapi_client.bal | 18 ++--- .../expected_gen/jira_openapi_service.bal | 10 +-- .../jira_openapi_service_with_type.bal | 12 ++-- .../expected_gen/petstore_schema_type.bal | 14 ++-- .../client/ballerina/delete_with_header.bal | 4 +- .../ballerina/multiline_param_comment.bal | 2 +- .../mock_client_for_advance_return_type.bal | 72 +++++++++---------- .../resource/ballerina/pathParameters.bal | 2 +- .../ballerina/listeners/listeners05.bal | 2 +- .../requestBody/additional_prop_types.bal | 18 ++--- .../requestBody/additional_property.bal | 2 +- .../requestBody/refactor_record_name.bal | 4 +- .../ballerina/response/scenario_09_rs.bal | 2 +- .../ballerina/response/scenario_12_rs.bal | 2 +- 16 files changed, 85 insertions(+), 84 deletions(-) diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/FunctionBodyNodeTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/FunctionBodyNodeTests.java index 869022568..495dcef27 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/FunctionBodyNodeTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/FunctionBodyNodeTests.java @@ -42,6 +42,7 @@ import java.util.Optional; import java.util.Set; +import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; import static io.ballerina.openapi.generators.common.GeneratorTestUtils.getOpenAPI; /** @@ -67,7 +68,7 @@ public void getFunctionBodyNodes(String yamlFile, String path, boolean hasHeader TypeHandler.createInstance(openapi, false); FunctionBodyGeneratorImp functionBodyGeneratorImp = new FunctionBodyGeneratorImp(path, operation, openapi, new AuthConfigGeneratorImp(false, false), - new BallerinaUtilGenerator(), new ArrayList<>(), hasHeaders, hasDefaultHeaders, hasQueries); + new BallerinaUtilGenerator(), new ArrayList<>(), hasHeaders, hasDefaultHeaders, hasQueries, HEADERS); Optional bodyNode = functionBodyGeneratorImp.getFunctionBodyNode(); content = content.trim().replaceAll("\n", "").replaceAll("\\s+", ""); String bodyNodeContent = bodyNode.get().toString().trim().replaceAll("\n", "") diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/RemoteFunctionNameValidationTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/RemoteFunctionNameValidationTests.java index e7126df38..b8a2000c1 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/RemoteFunctionNameValidationTests.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/client/RemoteFunctionNameValidationTests.java @@ -58,7 +58,7 @@ public void testFunctionNameGeneration(String operationId, String expectedFuncti public Object[][] dataProvider() { return new Object[][]{ {"get-pet-name", "getPetName"}, - {"GET_Add_permission", "gET_Add_permission"}, + {"GET_Add_Permission", "gETAddPermission"}, {"ListBankAccount", "listBankAccount"}, {"chat.media.download", "chatMediaDownload"} }; diff --git a/openapi-cli/src/test/resources/expected_gen/jira_openapi_client.bal b/openapi-cli/src/test/resources/expected_gen/jira_openapi_client.bal index e57bd4596..e8f506f8a 100644 --- a/openapi-cli/src/test/resources/expected_gen/jira_openapi_client.bal +++ b/openapi-cli/src/test/resources/expected_gen/jira_openapi_client.bal @@ -385,7 +385,7 @@ public isolated client class Client { return self.clientEp->delete(resourcePath, headers = headers); } - resource isolated function delete rest/atlassian\-connect/'1/app/module/dynamic(map headers = {}, *DynamicmodulesresourceRemovemodules_deleteQueries queries) returns http:Response|error { + resource isolated function delete rest/atlassian\-connect/'1/app/module/dynamic(map headers = {}, *DynamicModulesResourceRemoveModulesDeleteQueries queries) returns http:Response|error { string resourcePath = string `/rest/atlassian-connect/1/app/module/dynamic`; map queryParamEncoding = {"moduleKey": {style: FORM, explode: true}}; resourcePath = resourcePath + check getPathForQueryParam(queries, queryParamEncoding); @@ -3844,14 +3844,6 @@ public type GetChangeLogsQueries record { int:Signed32 startAt = 0; }; -# Represents the Queries record for the operation: DynamicModulesResource.removeModules_delete -public type DynamicmodulesresourceRemovemodules_deleteQueries record { - # The key of the module to remove. To include multiple module keys, provide multiple copies of this parameter. - # For example, `moduleKey=dynamic-attachment-entity-property&moduleKey=dynamic-select-field`. - # Nonexistent keys are ignored. - string[] moduleKey?; -}; - # Details of a field that can be used in advanced searches. public type FieldReferenceData record {| # The field identifier. @@ -5739,6 +5731,14 @@ public type JQLPersonalDataMigrationRequest record {| string[] queryStrings?; |}; +# Represents the Queries record for the operation: DynamicModulesResource.removeModules_delete +public type DynamicModulesResourceRemoveModulesDeleteQueries record { + # The key of the module to remove. To include multiple module keys, provide multiple copies of this parameter. + # For example, `moduleKey=dynamic-attachment-entity-property&moduleKey=dynamic-select-field`. + # Nonexistent keys are ignored. + string[] moduleKey?; +}; + # A page of items. public type PageBeanFieldConfigurationScheme record {| # The URL of the page. diff --git a/openapi-cli/src/test/resources/expected_gen/jira_openapi_service.bal b/openapi-cli/src/test/resources/expected_gen/jira_openapi_service.bal index 848213462..10f155ad3 100644 --- a/openapi-cli/src/test/resources/expected_gen/jira_openapi_service.bal +++ b/openapi-cli/src/test/resources/expected_gen/jira_openapi_service.bal @@ -571,7 +571,7 @@ service / on ep0 { resource function get rest/api/'2/project/[string projectIdOrKey]/properties/[string propertyKey]() returns EntityProperty|http:BadRequest|http:Unauthorized|http:Forbidden|http:NotFound { } - resource function get rest/api/'2/project/[string projectIdOrKey]/role() returns RestApi2ProjectProjectidorkeyRoleResponse|http:Unauthorized|http:NotFound { + resource function get rest/api/'2/project/[string projectIdOrKey]/role() returns RestApi2ProjectProjectIdOrKeyRoleResponse|http:Unauthorized|http:NotFound { } resource function get rest/api/'2/project/[string projectIdOrKey]/role/[int id]() returns ProjectRole|http:BadRequest|http:Unauthorized|http:NotFound { @@ -2604,10 +2604,6 @@ public type IssueTypeScreenSchemesProjects record {| string[] projectIds; |}; -public type RestApi2ProjectProjectidorkeyRoleResponse record {| - string...; -|}; - # Details of the identifiers for a created or updated remote issue link. public type RemoteIssueLinkIdentifies record {| # The ID of the remote issue link, such as the ID of the item on the remote system. @@ -5922,6 +5918,10 @@ public type CustomFieldUpdatedContextOptionsList record {| CustomFieldOptionUpdate[] options?; |}; +public type RestApi2ProjectProjectIdOrKeyRoleResponse record {| + string...; +|}; + # Details about system and custom avatars. public type Avatars record {| # System avatars list. diff --git a/openapi-cli/src/test/resources/expected_gen/jira_openapi_service_with_type.bal b/openapi-cli/src/test/resources/expected_gen/jira_openapi_service_with_type.bal index 333184b89..e1b2159e1 100644 --- a/openapi-cli/src/test/resources/expected_gen/jira_openapi_service_with_type.bal +++ b/openapi-cli/src/test/resources/expected_gen/jira_openapi_service_with_type.bal @@ -571,7 +571,7 @@ service OASServiceType / on ep0 { resource function get rest/api/'2/project/[string projectIdOrKey]/properties/[string propertyKey]() returns EntityProperty|http:BadRequest|http:Unauthorized|http:Forbidden|http:NotFound { } - resource function get rest/api/'2/project/[string projectIdOrKey]/role() returns RestApi2ProjectProjectidorkeyRoleResponse|http:Unauthorized|http:NotFound { + resource function get rest/api/'2/project/[string projectIdOrKey]/role() returns RestApi2ProjectProjectIdOrKeyRoleResponse|http:Unauthorized|http:NotFound { } resource function get rest/api/'2/project/[string projectIdOrKey]/role/[int id]() returns ProjectRole|http:BadRequest|http:Unauthorized|http:NotFound { @@ -1519,7 +1519,7 @@ type OASServiceType service object { resource function put rest/api/'2/project/[string projectIdOrKey]/properties/[string propertyKey](@http:Payload json payload) returns json|JsonCreated|http:BadRequest|http:Unauthorized|http:Forbidden|http:NotFound; resource function delete rest/api/'2/project/[string projectIdOrKey]/properties/[string propertyKey]() returns http:NoContent|http:BadRequest|http:Unauthorized|http:Forbidden|http:NotFound; resource function post rest/api/'2/project/[string projectIdOrKey]/restore() returns ProjectOk|http:BadRequest|http:Unauthorized|http:NotFound; - resource function get rest/api/'2/project/[string projectIdOrKey]/role() returns RestApi2ProjectProjectidorkeyRoleResponse|http:Unauthorized|http:NotFound; + resource function get rest/api/'2/project/[string projectIdOrKey]/role() returns RestApi2ProjectProjectIdOrKeyRoleResponse|http:Unauthorized|http:NotFound; resource function get rest/api/'2/project/[string projectIdOrKey]/role/[int id]() returns ProjectRole|http:BadRequest|http:Unauthorized|http:NotFound; resource function put rest/api/'2/project/[string projectIdOrKey]/role/[int id](@http:Payload ProjectRoleActorsUpdateBean payload) returns ProjectRole|http:BadRequest|http:Unauthorized|http:NotFound; resource function post rest/api/'2/project/[string projectIdOrKey]/role/[int id](@http:Payload ActorsMap payload) returns ProjectRoleOk|http:BadRequest|http:Unauthorized|http:NotFound; @@ -3025,10 +3025,6 @@ public type IssueTypeScreenSchemesProjects record {| string[] projectIds; |}; -public type RestApi2ProjectProjectidorkeyRoleResponse record {| - string...; -|}; - # Details of the identifiers for a created or updated remote issue link. public type RemoteIssueLinkIdentifies record {| # The ID of the remote issue link, such as the ID of the item on the remote system. @@ -6343,6 +6339,10 @@ public type CustomFieldUpdatedContextOptionsList record {| CustomFieldOptionUpdate[] options?; |}; +public type RestApi2ProjectProjectIdOrKeyRoleResponse record {| + string...; +|}; + # Details about system and custom avatars. public type Avatars record {| # System avatars list. diff --git a/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal b/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal index bef3019f2..2dd54d13a 100644 --- a/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal +++ b/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal @@ -3,12 +3,6 @@ import ballerina/http; -# Represents the Queries record for the operation: operation_get_/pets -public type Operation_get_PetsQueries record { - # Number of retriving items - int:Signed32 offset; -}; - # Provides settings related to HTTP/1.x protocol. public type ClientHttp1Settings record {| # Specifies whether to reuse a connection for multiple requests @@ -20,10 +14,16 @@ public type ClientHttp1Settings record {| |}; # Represents the Queries record for the operation: operation_get_/hello -public type Operation_get_HelloQueries record { +public type OperationGetHelloQueries record { string pet?; }; +# Represents the Queries record for the operation: operation_get_/pets +public type OperationGetPetsQueries record { + # Number of retriving items + int:Signed32 offset; +}; + # Proxy server configurations to be used with the HTTP client endpoint. public type ProxyConfig record {| # Host name of the proxy server diff --git a/openapi-cli/src/test/resources/generators/client/ballerina/delete_with_header.bal b/openapi-cli/src/test/resources/generators/client/ballerina/delete_with_header.bal index 64b6caf6a..be2fd36a8 100644 --- a/openapi-cli/src/test/resources/generators/client/ballerina/delete_with_header.bal +++ b/openapi-cli/src/test/resources/generators/client/ballerina/delete_with_header.bal @@ -63,7 +63,7 @@ public isolated client class Client { # + risk_id - Order Risk ID # + headers - Headers to be sent with the request # + return - Status OK - remote isolated function delete_order_risk(string order_id, string risk_id, map headers = {}) returns error? { + remote isolated function deleteOrderRisk(string order_id, string risk_id, map headers = {}) returns error? { string resourcePath = string `/admin/api/2021-10/orders/${getEncodedUri(order_id)}/risks/${getEncodedUri(risk_id)}.json`; return self.clientEp->delete(resourcePath, headers = headers); } @@ -72,7 +72,7 @@ public isolated client class Client { # # + headers - Headers to be sent with the request # + return - Status OK - remote isolated function order_risk(json payload, map headers = {}) returns error? { + remote isolated function orderRisk(json payload, map headers = {}) returns error? { string resourcePath = string `/request-body`; http:Request request = new; request.setPayload(payload, "application/json"); diff --git a/openapi-cli/src/test/resources/generators/client/file_provider/ballerina/multiline_param_comment.bal b/openapi-cli/src/test/resources/generators/client/file_provider/ballerina/multiline_param_comment.bal index 21f2ac83e..f76cedc62 100644 --- a/openapi-cli/src/test/resources/generators/client/file_provider/ballerina/multiline_param_comment.bal +++ b/openapi-cli/src/test/resources/generators/client/file_provider/ballerina/multiline_param_comment.bal @@ -46,7 +46,7 @@ public isolated client class Client { # + headers - Headers to be sent with the request # + queries - Queries to be sent with the request # + return - Success - remote isolated function fineTunes_GetEvents(string fine\-tune\-id, map headers = {}, *FineTunes_GetEventsQueries queries) returns EventList|error { + remote isolated function fineTunesGetEvents(string fine\-tune\-id, map headers = {}, *FineTunesGetEventsQueries queries) returns EventList|error { string resourcePath = string `/fine-tunes/${getEncodedUri(fine\-tune\-id)}/events`; resourcePath = resourcePath + check getPathForQueryParam(queries); map headerValues = {...headers}; diff --git a/openapi-cli/src/test/resources/generators/client/mock/mock_client_for_advance_return_type.bal b/openapi-cli/src/test/resources/generators/client/mock/mock_client_for_advance_return_type.bal index 8773125ab..9c030423b 100644 --- a/openapi-cli/src/test/resources/generators/client/mock/mock_client_for_advance_return_type.bal +++ b/openapi-cli/src/test/resources/generators/client/mock/mock_client_for_advance_return_type.bal @@ -31,7 +31,7 @@ public isolated client class Client { # + headers - Headers to be sent with the request # + queries - Queries to be sent with the request @MethodImpl {name: "UpdateAccountAgentImpl"} - resource isolated function post api/v1/accounts/[string account_id]/update_agent(map headers = {}, typedesc targetType = <>, *UpdateAccountAgentQueries queries) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function post api/v1/accounts/[string account_id]/update_agent(map headers = {}, typedesc targetType = <>, *UpdateAccountAgentQueries queries) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; # Update account status # @@ -39,19 +39,19 @@ public isolated client class Client { # + headers - Headers to be sent with the request # + queries - Queries to be sent with the request @MethodImpl {name: "UpdateAccountImpl"} - resource isolated function post api/v1/accounts/[string account_id]/update_status(map headers = {}, typedesc targetType = <>, *UpdateAccountQueries queries) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function post api/v1/accounts/[string account_id]/update_status(map headers = {}, typedesc targetType = <>, *UpdateAccountQueries queries) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; # Execute payments # # + headers - Headers to be sent with the request @MethodImpl {name: "UpdateExecutePaymentsImpl"} - resource isolated function post api/v1/payments/execute_payments(payments_execute_payments_body payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; + resource isolated function post api/v1/payments/execute_payments(payments_execute_payments_body payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; # Submit a payment to retry cycle # # + headers - Headers to be sent with the request @MethodImpl {name: "UpdateSubmitPaymentToCycleImpl"} - resource isolated function post api/v1/payments/submit_failed_payment(payments_submit_failed_payment_body payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; + resource isolated function post api/v1/payments/submit_failed_payment(payments_submit_failed_payment_body payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; # Create an ad hoc statement run # @@ -69,13 +69,13 @@ public isolated client class Client { # # + headers - Headers to be sent with the request @MethodImpl {name: "createPaymentRunImpl"} - resource isolated function post api/v1/subscription_payment_runs(POSTPaymentRun payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; + resource isolated function post api/v1/subscription_payment_runs(POSTPaymentRun payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; # Create a payment run schedule # # + headers - Headers to be sent with the request @MethodImpl {name: "createPaymentRunScheduleImpl"} - resource isolated function post api/v1/payment_run_schedules(POSTPaymentRunSchedule payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; + resource isolated function post api/v1/payment_run_schedules(POSTPaymentRunSchedule payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; # Cancel a payment run schedule # @@ -85,13 +85,13 @@ public isolated client class Client { resource isolated function delete api/v1/payment_run_schedules/[int schedule_id](map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @MethodImpl {name: "executeExecuteAccountPaymentsImpl"} - resource isolated function put api/v1/payments/execute_account_payments/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function put api/v1/payments/execute_account_payments/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @MethodImpl {name: "executeExecuteDebitMemoPaymentImpl"} - resource isolated function put api/v1/payments/execute_debit_memo_payment/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function put api/v1/payments/execute_debit_memo_payment/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @MethodImpl {name: "executeExecuteInvoicePaymentImpl"} - resource isolated function put api/v1/payments/execute_invoice_payment/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function put api/v1/payments/execute_invoice_payment/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @MethodImpl {name: "getAccountCycleHistoryImpl"} resource isolated function get api/v1/payments/account_cycle_history/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @@ -194,13 +194,13 @@ public isolated client class Client { resource isolated function get api/v1/fetch_settings(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResourceWithoutPath"} external; @MethodImpl {name: "removeAccountFromCycleImpl"} - resource isolated function put api/v1/payments/remove_account_from_retry_cycle/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function put api/v1/payments/remove_account_from_retry_cycle/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @MethodImpl {name: "removeDebitMemoFromCycleImpl"} - resource isolated function put api/v1/payments/remove_debit_memo_from_retry_cycle/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function put api/v1/payments/remove_debit_memo_from_retry_cycle/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; @MethodImpl {name: "removeRemoveInoviceFromCycleImpl"} - resource isolated function put api/v1/payments/remove_invoice_from_retry_cycle/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; + resource isolated function put api/v1/payments/remove_invoice_from_retry_cycle/\(map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; # Update a payment run schedule # @@ -209,26 +209,26 @@ public isolated client class Client { @MethodImpl {name: "updatePaymentRunScheduleImpl"} resource isolated function put api/v1/payment_run_schedules/[int schedule_id](PUTPaymentRunSchedule payload, map headers = {}, typedesc targetType = <>) returns targetType|error = @java:Method {'class: "io.ballerina.openapi.client.GeneratedClient", name: "invokeResource"} external; - private isolated function UpdateAccountAgentImpl(string account_id, map headers, typedesc targetType, *UpdateAccountAgentQueries queries) returns http:StatusCodeResponse|error { - return { + private isolated function UpdateAccountAgentImpl(string account_id, map headers, typedesc targetType, *UpdateAccountAgentQueries queries) returns http:StatusCodeResponse|error { + return { body: {"success": true} }; } - private isolated function UpdateAccountImpl(string account_id, map headers, typedesc targetType, *UpdateAccountQueries queries) returns http:StatusCodeResponse|error { - return { + private isolated function UpdateAccountImpl(string account_id, map headers, typedesc targetType, *UpdateAccountQueries queries) returns http:StatusCodeResponse|error { + return { body: {"success": true} }; } - private isolated function UpdateExecutePaymentsImpl(payments_execute_payments_body payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function UpdateExecutePaymentsImpl(payments_execute_payments_body payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs enqueued for processing: [100, 101, 110, 111, 121]"} }; } - private isolated function UpdateSubmitPaymentToCycleImpl(payments_submit_failed_payment_body payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function UpdateSubmitPaymentToCycleImpl(payments_submit_failed_payment_body payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payment entered into retry process"} }; } @@ -245,14 +245,14 @@ public isolated client class Client { }; } - private isolated function createPaymentRunImpl(POSTPaymentRun payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function createPaymentRunImpl(POSTPaymentRun payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"id": 6, "success": "true"} }; } - private isolated function createPaymentRunScheduleImpl(POSTPaymentRunSchedule payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function createPaymentRunScheduleImpl(POSTPaymentRunSchedule payload, map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"id": 6, "success": "true"} }; } @@ -263,20 +263,20 @@ public isolated client class Client { }; } - private isolated function executeExecuteAccountPaymentsImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function executeExecuteAccountPaymentsImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs enqueued for processing: [310, 311, 312]"} }; } - private isolated function executeExecuteDebitMemoPaymentImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function executeExecuteDebitMemoPaymentImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs enqueued for processing: [300]"} }; } - private isolated function executeExecuteInvoicePaymentImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function executeExecuteInvoicePaymentImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs enqueued for processing: [290, 291]"} }; } @@ -395,20 +395,20 @@ public isolated client class Client { }; } - private isolated function removeAccountFromCycleImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function removeAccountFromCycleImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs have been removed from the retry cycle: [310, 311, 312]"} }; } - private isolated function removeDebitMemoFromCycleImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function removeDebitMemoFromCycleImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs have been removed from the retry cycle: [301]"} }; } - private isolated function removeRemoveInoviceFromCycleImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { - return { + private isolated function removeRemoveInoviceFromCycleImpl(map headers, typedesc targetType) returns http:StatusCodeResponse|error { + return { body: {"success": true, "message": "Payments with the following IDs have been removed from the retry cycle: [290, 291]"} }; } diff --git a/openapi-cli/src/test/resources/generators/client/resource/ballerina/pathParameters.bal b/openapi-cli/src/test/resources/generators/client/resource/ballerina/pathParameters.bal index b75e6976d..d1367b5c1 100644 --- a/openapi-cli/src/test/resources/generators/client/resource/ballerina/pathParameters.bal +++ b/openapi-cli/src/test/resources/generators/client/resource/ballerina/pathParameters.bal @@ -48,7 +48,7 @@ public isolated client class Client { # + headers - Headers to be sent with the request # + queries - Queries to be sent with the request # + return - Requested customer - resource isolated function get admin/api/'2021\-10/customers/[string customer_id](map headers = {}, *Get_customerQueries queries) returns error? { + resource isolated function get admin/api/'2021\-10/customers/[string customer_id](map headers = {}, *GetCustomerQueries queries) returns error? { string resourcePath = string `/admin/api/2021-10/customers/${getEncodedUri(customer_id)}`; resourcePath = resourcePath + check getPathForQueryParam(queries); return self.clientEp->get(resourcePath, headers); diff --git a/openapi-cli/src/test/resources/generators/service/ballerina/listeners/listeners05.bal b/openapi-cli/src/test/resources/generators/service/ballerina/listeners/listeners05.bal index e34a30c44..50051af37 100644 --- a/openapi-cli/src/test/resources/generators/service/ballerina/listeners/listeners05.bal +++ b/openapi-cli/src/test/resources/generators/service/ballerina/listeners/listeners05.bal @@ -7,6 +7,6 @@ service / on ep0 { # # + payload - Content of the request # + return - Successful operation - resource function post handle\-request(@http:Payload HandleRequest_RequestBody payload) returns HandleResponse_RequestBodyOk { + resource function post handle\-request(@http:Payload HandleRequest_RequestBody payload) returns HandleResponseRequestBodyOk { } } diff --git a/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_prop_types.bal b/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_prop_types.bal index c593459c4..4271d5f86 100644 --- a/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_prop_types.bal +++ b/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_prop_types.bal @@ -1,11 +1,3 @@ -public type ApiHistoricosimulacaoAddhistoricoRequest_2 record {| - record {|string...;|}...; -|}; - -public type ApiHistoricosimulacaoAddhistoricoRequest_1 record {| - HistoricoSimulacaoViewModel...; -|}; - public type Mailing_AddContact_body record { string name?; }; @@ -32,7 +24,7 @@ public type Mailing_AddContact_body_3 record {| MailingViewModel...; |}; -public type ApiHistoricosimulacaoAddhistoricoRequest record {| +public type ApiHistoricoSimulacaoAddHistoricoRequest record {| string...; |}; @@ -42,3 +34,11 @@ public type HistoricoSimulacaoViewModel record {| string? step?; string? descricao?; |}; + +public type ApiHistoricoSimulacaoAddHistoricoRequest_2 record {| + record {|string...;|}...; +|}; + +public type ApiHistoricoSimulacaoAddHistoricoRequest_1 record {| + HistoricoSimulacaoViewModel...; +|}; diff --git a/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_property.bal b/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_property.bal index 517d8cb40..4613fcee4 100644 --- a/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_property.bal +++ b/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/additional_property.bal @@ -7,7 +7,7 @@ service / on ep0 { # # + payload - parameter description # + return - Success - resource function post api/HistoricoSimulacao/AddHistorico(@http:Payload ApiHistoricosimulacaoAddhistoricoRequest|ApiHistoricosimulacaoAddhistoricoRequest_1|ApiHistoricosimulacaoAddhistoricoRequest_2 payload) returns http:Ok { + resource function post api/HistoricoSimulacao/AddHistorico(@http:Payload ApiHistoricoSimulacaoAddHistoricoRequest|ApiHistoricoSimulacaoAddHistoricoRequest_1|ApiHistoricoSimulacaoAddHistoricoRequest_2 payload) returns http:Ok { } # Description # diff --git a/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/refactor_record_name.bal b/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/refactor_record_name.bal index f456f5df2..dc946aa5f 100644 --- a/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/refactor_record_name.bal +++ b/openapi-cli/src/test/resources/generators/service/ballerina/requestBody/refactor_record_name.bal @@ -7,12 +7,12 @@ service / on ep0 { # # + payload - Content of the request # + return - Successful operation - resource function post handle\-request(@http:Payload HandleRequest_RequestBody payload) returns HandleResponse_RequestBodyOk { + resource function post handle\-request(@http:Payload HandleRequest_RequestBody payload) returns HandleResponseRequestBodyOk { } # Handle Response # # + payload - Content of the request # + return - Successful operation - resource function post handle\-response(@http:Payload HandleRequest_RequestBody payload) returns HandleResponse_RequestBodyOk { + resource function post handle\-response(@http:Payload HandleRequest_RequestBody payload) returns HandleResponseRequestBodyOk { } } diff --git a/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_09_rs.bal b/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_09_rs.bal index 44ba66c6c..73eff24c4 100644 --- a/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_09_rs.bal +++ b/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_09_rs.bal @@ -6,6 +6,6 @@ service /v1 on ep0 { # Creates a new pets. # # + return - A User object - resource function post pets() returns Inline_response_400BadRequest { + resource function post pets() returns InlineResponse400BadRequest { } } diff --git a/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_12_rs.bal b/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_12_rs.bal index 3a0293c12..6d59af821 100644 --- a/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_12_rs.bal +++ b/openapi-cli/src/test/resources/generators/service/ballerina/response/scenario_12_rs.bal @@ -6,6 +6,6 @@ service /v1 on ep0 { # Creates a new pets. # # + return - A JSON object containing pet information - resource function post pets() returns Inline_response_400BadRequest { + resource function post pets() returns InlineResponse400BadRequest { } } From 5a162d2fad4d3ab22f538d7b828715b28fa2e2c0 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 11:51:03 +0530 Subject: [PATCH 04/13] Fix spot bug failure --- .../generators/client/RemoteFunctionSignatureGenerator.java | 5 ++--- .../client/ResourceFunctionSignatureGenerator.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java index 7ce31c46d..8b63a327b 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java @@ -165,9 +165,8 @@ protected ParametersInfo getParametersInfo(List parameters) { if (parameters != null) { populateQueryAndHeaderParameters(parameters, queryParameters, headerParameters, pathParameters); - List nonHeaderParameters = new ArrayList<>(queryParameters) {{ - addAll(pathParameters); - }}; + List nonHeaderParameters = new ArrayList<>(queryParameters); + nonHeaderParameters.addAll(pathParameters); HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, openAPI, operation, httpMethod, path, nonHeaderParameters); Optional headers; diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java index 782b8df57..f269d5cab 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java @@ -148,9 +148,8 @@ protected ParametersInfo getParametersInfo(List parameters) { if (parameters != null) { populateHeaderAndQueryParameters(parameters, queryParameters, headerParameters, pathParameters); - List nonHeaderParameters = new ArrayList<>(queryParameters) {{ - addAll(pathParameters); - }}; + List nonHeaderParameters = new ArrayList<>(queryParameters); + nonHeaderParameters.addAll(pathParameters); HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, openAPI, operation, httpMethod, path, nonHeaderParameters); Optional headers; From 9a507a5e4232aaf1ebad1b0e95b0bb63e76095e7 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 12:58:53 +0530 Subject: [PATCH 05/13] Fix integration tests --- .../client/expected/project-09/client.bal | 10 +++++----- .../client/expected/project-09/types.bal | 20 +++++++++---------- .../content_schema_has_one_of_type.bal | 10 +++++----- .../ballerina/response_has_inline_record.bal | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/openapi-integration-tests/src/test/resources/client/expected/project-09/client.bal b/openapi-integration-tests/src/test/resources/client/expected/project-09/client.bal index a8a3d6f4c..e078597ca 100644 --- a/openapi-integration-tests/src/test/resources/client/expected/project-09/client.bal +++ b/openapi-integration-tests/src/test/resources/client/expected/project-09/client.bal @@ -56,7 +56,7 @@ public isolated client class Client { # + queries - Queries to be sent with the request # + return - OK @display {label: "Create Chat Completion"} - resource isolated function post deployments/[string deployment\-id]/chat/completions(createChatCompletionRequest payload, map headers = {}, *ChatCompletions_CreateQueries queries) returns createChatCompletionResponse|error { + resource isolated function post deployments/[string deployment\-id]/chat/completions(createChatCompletionRequest payload, map headers = {}, *ChatCompletionsCreateQueries queries) returns createChatCompletionResponse|error { string resourcePath = string `/deployments/${getEncodedUri(deployment\-id)}/chat/completions`; map headerValues = {...headers}; if self.apiKeyConfig is ApiKeysConfig { @@ -72,11 +72,11 @@ public isolated client class Client { # Using extensions to creates a completion for the chat messages. # - # + headers - Headers to be sent with the request - # + queries - Queries to be sent with the request - # + return - OK + # + headers - Headers to be sent with the request + # + queries - Queries to be sent with the request + # + return - OK @display {label: "Create Extensions Chat Completion"} - resource isolated function post deployments/[string deployment\-id]/extensions/chat/completions(extensionsChatCompletionsRequest payload, map headers = {}, *ExtensionsChatCompletions_CreateQueries queries) returns extensionsChatCompletionsResponse|error { + resource isolated function post deployments/[string deployment\-id]/extensions/chat/completions(extensionsChatCompletionsRequest payload, map headers = {}, *ExtensionsChatCompletionsCreateQueries queries) returns extensionsChatCompletionsResponse|error { string resourcePath = string `/deployments/${getEncodedUri(deployment\-id)}/extensions/chat/completions`; map headerValues = {...headers}; if self.apiKeyConfig is ApiKeysConfig { diff --git a/openapi-integration-tests/src/test/resources/client/expected/project-09/types.bal b/openapi-integration-tests/src/test/resources/client/expected/project-09/types.bal index c2271ed7e..567670a51 100644 --- a/openapi-integration-tests/src/test/resources/client/expected/project-09/types.bal +++ b/openapi-integration-tests/src/test/resources/client/expected/project-09/types.bal @@ -26,11 +26,6 @@ public type promptFilterResults promptFilterResult[]; public type chatCompletionFunctionParameters record { }; -# Represents the Queries record for the operation: ChatCompletions_Create -public type ChatCompletions_CreateQueries record { - string api\-version; -}; - public type chatCompletionRequestMessage record { # The role of the messages author. One of `system`, `user`, `assistant`, or `function`. "system"|"user"|"assistant"|"function" role; @@ -133,6 +128,11 @@ public type extensionsChatCompletionsRequest record { dataSource[] dataSources?; }; +# Represents the Queries record for the operation: ExtensionsChatCompletions_Create +public type ExtensionsChatCompletionsCreateQueries record { + string api\-version; +}; + # Error information returned by the service. public type errorBase record { # The error code. @@ -213,6 +213,11 @@ public type chatCompletionResponseMessage record { chatCompletionRequestMessage_function_call function_call?; }; +# Represents the Queries record for the operation: ChatCompletions_Create +public type ChatCompletionsCreateQueries record { + string api\-version; +}; + public type extensionsChatCompletionChoice record { *chatCompletionChoiceCommon; message message?; @@ -226,11 +231,6 @@ public type chatCompletionsResponseCommon record { chatCompletionsResponseCommon_usage usage?; }; -# Represents the Queries record for the operation: ExtensionsChatCompletions_Create -public type ExtensionsChatCompletions_CreateQueries record { - string api\-version; -}; - # Provides settings related to HTTP/1.x protocol. public type ClientHttp1Settings record {| # Specifies whether to reuse a connection for multiple requests diff --git a/openapi-integration-tests/src/test/resources/service/return/ballerina/content_schema_has_one_of_type.bal b/openapi-integration-tests/src/test/resources/service/return/ballerina/content_schema_has_one_of_type.bal index 323ce23bd..e1d9b35c1 100644 --- a/openapi-integration-tests/src/test/resources/service/return/ballerina/content_schema_has_one_of_type.bal +++ b/openapi-integration-tests/src/test/resources/service/return/ballerina/content_schema_has_one_of_type.bal @@ -3,11 +3,6 @@ import ballerina/http; -public type Inline_response_200Ok record {| - *http:Ok; - inline_response_200 body; -|}; - public type User record { string userName; string firstName?; @@ -20,6 +15,11 @@ public type PetForm record { string lastName?; }; +public type InlineResponse200Ok record {| + *http:Ok; + inline_response_200 body; +|}; + public type inline_response_200 User|Pet|PetForm; public type Pet record { diff --git a/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal b/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal index 5168525a4..0ebec178a 100644 --- a/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal +++ b/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal @@ -3,7 +3,7 @@ import ballerina/http; -public type Inline_response_400BadRequest record {| +public type InlineResponse400BadRequest record {| *http:BadRequest; inline_response_400 body; |}; From 4856f170ff2673b3b0934012358ec1c226e158f5 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 13:58:13 +0530 Subject: [PATCH 06/13] Refactor function body generators --- .../AbstractFunctionSignatureGenerator.java | 278 ++++++++++++++++++ .../RemoteFunctionSignatureGenerator.java | 275 ++--------------- .../ResourceFunctionSignatureGenerator.java | 260 +--------------- .../parameter/HeadersParameterGenerator.java | 13 + .../core/generators/common/OASModifier.java | 31 +- 5 files changed, 332 insertions(+), 525 deletions(-) create mode 100644 openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java new file mode 100644 index 000000000..74cc4e8f1 --- /dev/null +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java @@ -0,0 +1,278 @@ +/* + * 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 + * 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.core.generators.client; + +import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; +import io.ballerina.compiler.syntax.tree.Node; +import io.ballerina.compiler.syntax.tree.NodeFactory; +import io.ballerina.compiler.syntax.tree.ParameterNode; +import io.ballerina.compiler.syntax.tree.RequiredParameterNode; +import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; +import io.ballerina.compiler.syntax.tree.SeparatedNodeList; +import io.ballerina.compiler.syntax.tree.Token; +import io.ballerina.openapi.core.generators.client.diagnostic.ClientDiagnostic; +import io.ballerina.openapi.core.generators.client.diagnostic.ClientDiagnosticImp; +import io.ballerina.openapi.core.generators.client.parameter.HeadersParameterGenerator; +import io.ballerina.openapi.core.generators.client.parameter.QueriesParameterGenerator; +import io.ballerina.openapi.core.generators.client.parameter.RequestBodyGenerator; +import io.ballerina.openapi.core.generators.common.exception.BallerinaOpenApiException; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.parameters.Parameter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createSeparatedNodeList; +import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createToken; +import static io.ballerina.compiler.syntax.tree.SyntaxKind.CLOSE_PAREN_TOKEN; +import static io.ballerina.compiler.syntax.tree.SyntaxKind.COMMA_TOKEN; +import static io.ballerina.compiler.syntax.tree.SyntaxKind.OPEN_PAREN_TOKEN; +import static io.ballerina.openapi.core.generators.client.diagnostic.DiagnosticMessages.OAS_CLIENT_100; +import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; +import static io.ballerina.openapi.core.generators.common.GeneratorUtils.extractReferenceType; + +public abstract class AbstractFunctionSignatureGenerator implements FunctionSignatureGenerator { + OpenAPI openAPI; + Operation operation; + List diagnostics = new ArrayList<>(); + FunctionReturnTypeGeneratorImp functionReturnTypeGenerator; + private final String httpMethod; + private final String path; + private String headersParamName = HEADERS; + + private boolean hasDefaultHeader = false; + private boolean hasHeadersParam = false; + private boolean hasQueriesParam = false; + + public AbstractFunctionSignatureGenerator(Operation operation, OpenAPI openAPI, String httpMethod, String path) { + this.operation = operation; + this.openAPI = openAPI; + this.httpMethod = httpMethod; + this.path = path; + this.functionReturnTypeGenerator = new FunctionReturnTypeGeneratorImp(operation, openAPI, httpMethod); + } + + @Override + public Optional generateFunctionSignature() { + List parameters = operation.getParameters(); + ParametersInfo parametersInfo = getParametersInfo(parameters); + + if (parametersInfo == null) { + return Optional.empty(); + } + + List paramList = getParameterNodes(parametersInfo); + SeparatedNodeList parameterNodes = createSeparatedNodeList(paramList); + + // 3. return statements + FunctionReturnTypeGeneratorImp functionReturnType = getFunctionReturnTypeGenerator(); + Optional returnType = functionReturnType.getReturnType(); + diagnostics.addAll(functionReturnType.getDiagnostics()); + if (returnType.isEmpty()) { + return Optional.empty(); + } + + //create function signature node + return returnType.map(returnTypeDescriptorNode -> NodeFactory.createFunctionSignatureNode( + createToken(OPEN_PAREN_TOKEN), parameterNodes, + createToken(CLOSE_PAREN_TOKEN), returnTypeDescriptorNode)); + } + + private static List getParameterNodes(ParametersInfo parametersInfo) { + List defaultableParams = parametersInfo.defaultableParams(); + List params = parametersInfo.requiredParams(); + List includedParam = parametersInfo.includedParam(); + + // Add defaultableParams parameters + if (!defaultableParams.isEmpty()) { + params.addAll(defaultableParams); + } + + // Add included record parameter + if (!includedParam.isEmpty()) { + params.addAll(includedParam); + } + + // Remove the last comma + if (!params.isEmpty()) { + params.remove(params.size() - 1); + } + return params; + } + + protected ParametersInfo getParametersInfo(List parameters) { + return getParametersInfoWithoutPath(parameters); + } + + protected ParametersInfo getParametersInfoWithoutPath(List parameters) { + List requiredParams = new ArrayList<>(); + List defaultableParams = new ArrayList<>(); + List includedParam = new ArrayList<>(); + Token comma = createToken(COMMA_TOKEN); + + List headerParameters = new ArrayList<>(); + List queryParameters = new ArrayList<>(); + List pathParameters = new ArrayList<>(); + + // requestBody + if (operation.getRequestBody() != null) { + RequestBodyGenerator requestBodyGenerator = new RequestBodyGenerator(operation.getRequestBody(), + openAPI); + Optional requestBody = requestBodyGenerator.generateParameterNode(); + if (requestBody.isEmpty()) { + diagnostics.addAll(requestBodyGenerator.getDiagnostics()); + return null; + } + headerParameters = requestBodyGenerator.getHeaderSchemas(); + requiredParams.add(requestBody.get()); + requiredParams.add(comma); + } + + // parameters - query, headers + if (parameters != null) { + populateHeaderAndQueryParameters(parameters, queryParameters, headerParameters, pathParameters); + + List nonHeaderParameters = new ArrayList<>(queryParameters); + nonHeaderParameters.addAll(pathParameters); + HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, + openAPI, operation, httpMethod, path, nonHeaderParameters); + Optional headers; + if (headerParameters.isEmpty()) { + hasDefaultHeader = true; + headers = HeadersParameterGenerator.getDefaultParameterNode(nonHeaderParameters); + } else { + headers = headersParameterGenerator.generateParameterNode(); + } + + diagnostics.addAll(headersParameterGenerator.getDiagnostics()); + if (headersParameterGenerator.hasErrors()) { + return null; + } + + if (headers.isPresent()) { + headersParamName = HeadersParameterGenerator.getHeadersParamName(headers.get()); + hasHeadersParam = true; + if (headers.get() instanceof RequiredParameterNode headerNode) { + requiredParams.add(headerNode); + requiredParams.add(comma); + } else { + defaultableParams.add(headers.get()); + defaultableParams.add(comma); + } + } else if (!headerParameters.isEmpty()) { + return null; + } + + QueriesParameterGenerator queriesParameterGenerator = new QueriesParameterGenerator(queryParameters, + openAPI, operation, httpMethod, path); + Optional queries = queriesParameterGenerator.generateParameterNode(); + diagnostics.addAll(queriesParameterGenerator.getDiagnostics()); + if (queriesParameterGenerator.hasErrors()) { + return null; + } + + if (queries.isPresent()) { + hasQueriesParam = true; + includedParam.add(queries.get()); + includedParam.add(comma); + } else if (!queryParameters.isEmpty()) { + return null; + } + } else { + ParameterNode defaultHeaderParam = HeadersParameterGenerator.getDefaultParameterNode().orElse(null); + if (defaultHeaderParam != null) { + headersParamName = HeadersParameterGenerator.getHeadersParamName(defaultHeaderParam); + hasDefaultHeader = true; + hasHeadersParam = true; + defaultableParams.add(defaultHeaderParam); + defaultableParams.add(comma); + } + } + return new ParametersInfo(requiredParams, defaultableParams, includedParam); + } + + private void populateHeaderAndQueryParameters(List parameters, List queryParameters, + List headerParameters, List pathParameters) { + for (Parameter parameter : parameters) { + if (parameter.get$ref() != null) { + String paramType = null; + try { + paramType = extractReferenceType(parameter.get$ref()); + } catch (BallerinaOpenApiException e) { + ClientDiagnosticImp clientDiagnostic = new ClientDiagnosticImp(OAS_CLIENT_100, + parameter.get$ref()); + diagnostics.add(clientDiagnostic); + } + parameter = openAPI.getComponents().getParameters().get(paramType); + } + + String in = parameter.getIn(); + + switch (in) { + case "query": + queryParameters.add(parameter); + break; + case "header": + headerParameters.add(parameter); + break; + case "path": + pathParameters.add(parameter); + break; + default: + break; + } + } + } + + protected FunctionReturnTypeGeneratorImp getFunctionReturnTypeGenerator() { + return functionReturnTypeGenerator; + } + + @Override + public List getDiagnostics() { + return diagnostics; + } + + public boolean hasDefaultHeaders() { + return hasDefaultHeader; + } + + public boolean hasHeaders() { + return hasHeadersParam; + } + + public boolean hasQueries() { + return hasQueriesParam; + } + + @Override + public boolean hasDefaultStatusCodeBinding() { + return functionReturnTypeGenerator.hasDefaultStatusCodeBinding(); + } + + @Override + public List getNonDefaultStatusCodes() { + return functionReturnTypeGenerator.getNonDefaultStatusCodes(); + } + + public String getHeadersParamName() { + return headersParamName; + } +} diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java index 8b63a327b..abeb937e1 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java @@ -18,284 +18,65 @@ package io.ballerina.openapi.core.generators.client; -import io.ballerina.compiler.syntax.tree.DefaultableParameterNode; -import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeFactory; import io.ballerina.compiler.syntax.tree.ParameterNode; -import io.ballerina.compiler.syntax.tree.RequiredParameterNode; -import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; -import io.ballerina.compiler.syntax.tree.SeparatedNodeList; import io.ballerina.compiler.syntax.tree.Token; -import io.ballerina.openapi.core.generators.client.diagnostic.ClientDiagnostic; -import io.ballerina.openapi.core.generators.client.diagnostic.ClientDiagnosticImp; -import io.ballerina.openapi.core.generators.client.parameter.HeadersParameterGenerator; import io.ballerina.openapi.core.generators.client.parameter.PathParameterGenerator; -import io.ballerina.openapi.core.generators.client.parameter.QueriesParameterGenerator; -import io.ballerina.openapi.core.generators.client.parameter.RequestBodyGenerator; -import io.ballerina.openapi.core.generators.common.exception.BallerinaOpenApiException; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.parameters.Parameter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; -import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createSeparatedNodeList; import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createToken; -import static io.ballerina.compiler.syntax.tree.SyntaxKind.CLOSE_PAREN_TOKEN; import static io.ballerina.compiler.syntax.tree.SyntaxKind.COMMA_TOKEN; -import static io.ballerina.compiler.syntax.tree.SyntaxKind.OPEN_PAREN_TOKEN; -import static io.ballerina.openapi.core.generators.client.diagnostic.DiagnosticMessages.OAS_CLIENT_100; -import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; -import static io.ballerina.openapi.core.generators.common.GeneratorUtils.extractReferenceType; -public class RemoteFunctionSignatureGenerator implements FunctionSignatureGenerator { - OpenAPI openAPI; - Operation operation; - List diagnostics = new ArrayList<>(); - FunctionReturnTypeGeneratorImp functionReturnTypeGenerator; - private final String httpMethod; - private final String path; - private String headersParamName = HEADERS; - - private boolean hasDefaultHeader = false; - private boolean hasHeadersParam = false; - private boolean hasQueriesParam = false; +public class RemoteFunctionSignatureGenerator extends AbstractFunctionSignatureGenerator { public RemoteFunctionSignatureGenerator(Operation operation, OpenAPI openAPI, String httpMethod, String path) { - this.operation = operation; - this.openAPI = openAPI; - this.httpMethod = httpMethod; - this.path = path; - this.functionReturnTypeGenerator = new FunctionReturnTypeGeneratorImp(operation, openAPI, httpMethod); - } - - @Override - public Optional generateFunctionSignature() { - List parameters = operation.getParameters(); - ParametersInfo parametersInfo = getParametersInfo(parameters); - - if (parametersInfo == null) { - return Optional.empty(); - } - - List paramList = getParameterNodes(parametersInfo); - SeparatedNodeList parameterNodes = createSeparatedNodeList(paramList); - - // 3. return statements - FunctionReturnTypeGeneratorImp returnTypeGenerator = getFunctionReturnTypeGenerator(); - Optional returnType = returnTypeGenerator.getReturnType(); - diagnostics.addAll(returnTypeGenerator.getDiagnostics()); - if (returnType.isEmpty()) { - return Optional.empty(); - } - - return returnType.map(returnTypeDescriptorNode -> NodeFactory.createFunctionSignatureNode( - createToken(OPEN_PAREN_TOKEN), parameterNodes, - createToken(CLOSE_PAREN_TOKEN), returnTypeDescriptorNode)); - } - - private static List getParameterNodes(ParametersInfo parametersInfo) { - List defaultableParams = parametersInfo.defaultableParams(); - List params = parametersInfo.requiredParams(); - List includedParam = parametersInfo.includedParam(); - - // Add defaultableParams parameters - if (!defaultableParams.isEmpty()) { - params.addAll(defaultableParams); - } - - // Add included record parameter - if (!includedParam.isEmpty()) { - params.addAll(includedParam); - } - - // Remove the last comma - if (!params.isEmpty()) { - params.remove(params.size() - 1); - } - return params; + super(operation, openAPI, httpMethod, path); } protected ParametersInfo getParametersInfo(List parameters) { - List requiredParams = new ArrayList<>(); - List defaultableParams = new ArrayList<>(); - List includedParam = new ArrayList<>(); + List requiredParams; + List defaultableParams; + List includedParam; Token comma = createToken(COMMA_TOKEN); - List headerParameters = new ArrayList<>(); - List queryParameters = new ArrayList<>(); - List pathParameters = new ArrayList<>(); + ParametersInfo parametersInfo = super.getParametersInfo(parameters); - // 1. path parameters - if (parameters != null) { - for (Parameter parameter : parameters) { - if (parameter.getIn().equals("path")) { - PathParameterGenerator paramGenerator = new PathParameterGenerator(parameter, openAPI); - Optional param = paramGenerator.generateParameterNode(); - if (param.isEmpty()) { - diagnostics.addAll(paramGenerator.getDiagnostics()); - return null; - } - // Path parameters are always required. - requiredParams.add(param.get()); - requiredParams.add(comma); - } - } + if (Objects.isNull(parameters)) { + return parametersInfo; } - // 1. requestBody - if (operation.getRequestBody() != null) { - RequestBodyGenerator requestBodyGenerator = new RequestBodyGenerator(operation.getRequestBody(), - openAPI); - Optional requestBody = requestBodyGenerator.generateParameterNode(); - if (requestBody.isEmpty()) { - diagnostics.addAll(requestBodyGenerator.getDiagnostics()); - return null; - } - headerParameters = requestBodyGenerator.getHeaderSchemas(); - requiredParams.add(requestBody.get()); - requiredParams.add(comma); + if (Objects.isNull(parametersInfo)) { + requiredParams = new ArrayList<>(); + defaultableParams = new ArrayList<>(); + includedParam = new ArrayList<>(); + } else { + requiredParams = parametersInfo.requiredParams(); + defaultableParams = parametersInfo.defaultableParams(); + includedParam = parametersInfo.includedParam(); } - // 2. parameters - query, headers - if (parameters != null) { - populateQueryAndHeaderParameters(parameters, queryParameters, headerParameters, pathParameters); - - List nonHeaderParameters = new ArrayList<>(queryParameters); - nonHeaderParameters.addAll(pathParameters); - HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, - openAPI, operation, httpMethod, path, nonHeaderParameters); - Optional headers; - if (headerParameters.isEmpty()) { - hasDefaultHeader = true; - headers = HeadersParameterGenerator.getDefaultParameterNode(nonHeaderParameters); - } else { - headers = headersParameterGenerator.generateParameterNode(); - } - - diagnostics.addAll(headersParameterGenerator.getDiagnostics()); - if (headersParameterGenerator.hasErrors()) { - return null; - } - - if (headers.isPresent()) { - populateHeadersParamName(headers.get()); - hasHeadersParam = true; - if (headers.get() instanceof RequiredParameterNode headerNode) { - requiredParams.add(headerNode); - requiredParams.add(comma); - } else { - defaultableParams.add(headers.get()); - defaultableParams.add(comma); + // path parameters + for (Parameter parameter : parameters) { + if (parameter.getIn().equals("path")) { + PathParameterGenerator paramGenerator = new PathParameterGenerator(parameter, openAPI); + Optional param = paramGenerator.generateParameterNode(); + if (param.isEmpty()) { + diagnostics.addAll(paramGenerator.getDiagnostics()); + return null; } - } else if (!headerParameters.isEmpty()) { - return null; - } - - QueriesParameterGenerator queriesParameterGenerator = new QueriesParameterGenerator(queryParameters, - openAPI, operation, httpMethod, path); - Optional queries = queriesParameterGenerator.generateParameterNode(); - diagnostics.addAll(queriesParameterGenerator.getDiagnostics()); - if (queriesParameterGenerator.hasErrors()) { - return null; - } - - if (queries.isPresent()) { - hasQueriesParam = true; - includedParam.add(queries.get()); - includedParam.add(comma); - } else if (!queryParameters.isEmpty()) { - return null; - } - } else { - ParameterNode defaultHeaderParam = HeadersParameterGenerator.getDefaultParameterNode().orElse(null); - if (defaultHeaderParam != null) { - populateHeadersParamName(defaultHeaderParam); - hasDefaultHeader = true; - hasHeadersParam = true; - defaultableParams.add(defaultHeaderParam); - defaultableParams.add(comma); + // Path parameters are always required. + requiredParams.add(param.get()); + requiredParams.add(comma); } } return new ParametersInfo(requiredParams, defaultableParams, includedParam); } - - private void populateHeadersParamName(ParameterNode parameterNode) { - if (parameterNode instanceof RequiredParameterNode requiredParameterNode && - requiredParameterNode.paramName().isPresent()) { - headersParamName = requiredParameterNode.paramName().get().text(); - } else if (parameterNode instanceof DefaultableParameterNode parameter && - parameter.paramName().isPresent()) { - headersParamName = parameter.paramName().get().text(); - } - } - - private void populateQueryAndHeaderParameters(List parameters, List queryParameters, - List headerParameters, List pathParameters) { - for (Parameter parameter : parameters) { - if (parameter.get$ref() != null) { - String paramType = null; - try { - paramType = extractReferenceType(parameter.get$ref()); - } catch (BallerinaOpenApiException e) { - ClientDiagnosticImp clientDiagnostic = new ClientDiagnosticImp(OAS_CLIENT_100, - parameter.get$ref()); - diagnostics.add(clientDiagnostic); - } - parameter = openAPI.getComponents().getParameters().get(paramType); - } - - String in = parameter.getIn(); - - switch (in) { - case "query": - queryParameters.add(parameter); - break; - case "header": - headerParameters.add(parameter); - break; - case "path": - pathParameters.add(parameter); - break; - default: - break; - } - } -} - - protected FunctionReturnTypeGeneratorImp getFunctionReturnTypeGenerator() { - return functionReturnTypeGenerator; - } - - public List getDiagnostics() { - return diagnostics; - } - - public boolean hasDefaultHeaders() { - return hasDefaultHeader; - } - - public boolean hasHeaders() { - return hasHeadersParam; - } - - public boolean hasQueries() { - return hasQueriesParam; - } - - public boolean hasDefaultStatusCodeBinding() { - return functionReturnTypeGenerator.hasDefaultStatusCodeBinding(); - } - - public List getNonDefaultStatusCodes() { - return functionReturnTypeGenerator.getNonDefaultStatusCodes(); - } - - public String getHeadersParamName() { - return headersParamName; - } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java index f269d5cab..e0ceec647 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/ResourceFunctionSignatureGenerator.java @@ -18,269 +18,13 @@ package io.ballerina.openapi.core.generators.client; -import io.ballerina.compiler.syntax.tree.DefaultableParameterNode; -import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; -import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeFactory; -import io.ballerina.compiler.syntax.tree.ParameterNode; -import io.ballerina.compiler.syntax.tree.RequiredParameterNode; -import io.ballerina.compiler.syntax.tree.ReturnTypeDescriptorNode; -import io.ballerina.compiler.syntax.tree.SeparatedNodeList; -import io.ballerina.compiler.syntax.tree.Token; -import io.ballerina.openapi.core.generators.client.diagnostic.ClientDiagnostic; -import io.ballerina.openapi.core.generators.client.diagnostic.ClientDiagnosticImp; -import io.ballerina.openapi.core.generators.client.parameter.HeadersParameterGenerator; -import io.ballerina.openapi.core.generators.client.parameter.QueriesParameterGenerator; -import io.ballerina.openapi.core.generators.client.parameter.RequestBodyGenerator; -import io.ballerina.openapi.core.generators.common.exception.BallerinaOpenApiException; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.parameters.Parameter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createSeparatedNodeList; -import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createToken; -import static io.ballerina.compiler.syntax.tree.SyntaxKind.CLOSE_PAREN_TOKEN; -import static io.ballerina.compiler.syntax.tree.SyntaxKind.COMMA_TOKEN; -import static io.ballerina.compiler.syntax.tree.SyntaxKind.OPEN_PAREN_TOKEN; -import static io.ballerina.openapi.core.generators.client.diagnostic.DiagnosticMessages.OAS_CLIENT_100; -import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; -import static io.ballerina.openapi.core.generators.common.GeneratorUtils.extractReferenceType; - -public class ResourceFunctionSignatureGenerator implements FunctionSignatureGenerator { - protected final Operation operation; - protected final OpenAPI openAPI; - protected final List diagnostics = new ArrayList<>(); - protected FunctionReturnTypeGeneratorImp functionReturnTypeGenerator; - private final String httpMethod; - private final String path; - private String headersParamName = HEADERS; - - private boolean hasDefaultHeader = false; - private boolean hasHeadersParam = false; - private boolean hasQueriesParam = false; +public class ResourceFunctionSignatureGenerator extends AbstractFunctionSignatureGenerator { public ResourceFunctionSignatureGenerator(Operation operation, OpenAPI openAPI, String httpMethod, String path) { - this.operation = operation; - this.openAPI = openAPI; - this.httpMethod = httpMethod; - this.path = path; - this.functionReturnTypeGenerator = new FunctionReturnTypeGeneratorImp(operation, openAPI, httpMethod); - } - - @Override - public Optional generateFunctionSignature() { - List parameters = operation.getParameters(); - ParametersInfo parametersInfo = getParametersInfo(parameters); - - if (parametersInfo == null) { - return Optional.empty(); - } - - List paramList = getParameterNodes(parametersInfo); - SeparatedNodeList parameterNodes = createSeparatedNodeList(paramList); - - // 3. return statements - FunctionReturnTypeGeneratorImp functionReturnType = getFunctionReturnTypeGenerator(); - Optional returnType = functionReturnType.getReturnType(); - diagnostics.addAll(functionReturnType.getDiagnostics()); - if (returnType.isEmpty()) { - return Optional.empty(); - } - - //create function signature node - return returnType.map(returnTypeDescriptorNode -> NodeFactory.createFunctionSignatureNode( - createToken(OPEN_PAREN_TOKEN), parameterNodes, - createToken(CLOSE_PAREN_TOKEN), returnTypeDescriptorNode)); - } - - private static List getParameterNodes(ParametersInfo parametersInfo) { - List defaultableParams = parametersInfo.defaultableParams(); - List params = parametersInfo.requiredParams(); - List includedParam = parametersInfo.includedParam(); - - // Add defaultable parameters - if (!defaultableParams.isEmpty()) { - params.addAll(defaultableParams); - } - - // Add included record parameter - if (!includedParam.isEmpty()) { - params.addAll(includedParam); - } - - // Remove the last comma - if (!params.isEmpty()) { - params.remove(params.size() - 1); - } - return params; - } - - protected ParametersInfo getParametersInfo(List parameters) { - List requiredParams = new ArrayList<>(); - List defaultableParams = new ArrayList<>(); - List includedParam = new ArrayList<>(); - Token comma = createToken(COMMA_TOKEN); - - List headerParameters = new ArrayList<>(); - List queryParameters = new ArrayList<>(); - List pathParameters = new ArrayList<>(); - - // 1. requestBody - if (operation.getRequestBody() != null) { - RequestBodyGenerator requestBodyGenerator = new RequestBodyGenerator(operation.getRequestBody(), - openAPI); - Optional requestBody = requestBodyGenerator.generateParameterNode(); - if (requestBody.isEmpty()) { - diagnostics.addAll(requestBodyGenerator.getDiagnostics()); - return null; - } - headerParameters = requestBodyGenerator.getHeaderSchemas(); - requiredParams.add(requestBody.get()); - requiredParams.add(comma); - } - - // 2. parameters - query, requestBody, headers - if (parameters != null) { - populateHeaderAndQueryParameters(parameters, queryParameters, headerParameters, pathParameters); - - List nonHeaderParameters = new ArrayList<>(queryParameters); - nonHeaderParameters.addAll(pathParameters); - HeadersParameterGenerator headersParameterGenerator = new HeadersParameterGenerator(headerParameters, - openAPI, operation, httpMethod, path, nonHeaderParameters); - Optional headers; - if (headerParameters.isEmpty()) { - hasDefaultHeader = true; - headers = HeadersParameterGenerator.getDefaultParameterNode(nonHeaderParameters); - } else { - headers = headersParameterGenerator.generateParameterNode(); - } - - diagnostics.addAll(headersParameterGenerator.getDiagnostics()); - if (headersParameterGenerator.hasErrors()) { - return null; - } - - if (headers.isPresent()) { - populateHeadersParamName(headers.get()); - hasHeadersParam = true; - if (headers.get() instanceof RequiredParameterNode headerNode) { - requiredParams.add(headerNode); - requiredParams.add(comma); - } else { - defaultableParams.add(headers.get()); - defaultableParams.add(comma); - } - } else if (!headerParameters.isEmpty()) { - return null; - } - - QueriesParameterGenerator queriesParameterGenerator = new QueriesParameterGenerator(queryParameters, - openAPI, operation, httpMethod, path); - Optional queries = queriesParameterGenerator.generateParameterNode(); - diagnostics.addAll(queriesParameterGenerator.getDiagnostics()); - if (queriesParameterGenerator.hasErrors()) { - return null; - } - - if (queries.isPresent()) { - hasQueriesParam = true; - includedParam.add(queries.get()); - includedParam.add(comma); - } else if (!queryParameters.isEmpty()) { - return null; - } - } else { - ParameterNode defaultHeaderParam = HeadersParameterGenerator.getDefaultParameterNode().orElse(null); - if (defaultHeaderParam != null) { - populateHeadersParamName(defaultHeaderParam); - hasDefaultHeader = true; - hasHeadersParam = true; - defaultableParams.add(defaultHeaderParam); - defaultableParams.add(comma); - } - } - - return new ParametersInfo(requiredParams, defaultableParams, includedParam); - } - - private void populateHeadersParamName(ParameterNode parameterNode) { - if (parameterNode instanceof RequiredParameterNode requiredParameterNode && - requiredParameterNode.paramName().isPresent()) { - headersParamName = requiredParameterNode.paramName().get().text(); - } else if (parameterNode instanceof DefaultableParameterNode parameter && - parameter.paramName().isPresent()) { - headersParamName = parameter.paramName().get().text(); - } - } - - private void populateHeaderAndQueryParameters(List parameters, List queryParameters, - List headerParameters, List pathParameters) { - for (Parameter parameter : parameters) { - if (parameter.get$ref() != null) { - String paramType = null; - try { - paramType = extractReferenceType(parameter.get$ref()); - } catch (BallerinaOpenApiException e) { - ClientDiagnosticImp clientDiagnostic = new ClientDiagnosticImp(OAS_CLIENT_100, - parameter.get$ref()); - diagnostics.add(clientDiagnostic); - } - parameter = openAPI.getComponents().getParameters().get(paramType); - } - - String in = parameter.getIn(); - - switch (in) { - case "query": - queryParameters.add(parameter); - break; - case "header": - headerParameters.add(parameter); - break; - case "path": - pathParameters.add(parameter); - break; - default: - break; - } - } - } - - protected FunctionReturnTypeGeneratorImp getFunctionReturnTypeGenerator() { - return functionReturnTypeGenerator; - } - - @Override - public List getDiagnostics() { - return diagnostics; - } - - public boolean hasDefaultHeaders() { - return hasDefaultHeader; - } - - public boolean hasHeaders() { - return hasHeadersParam; - } - - public boolean hasQueries() { - return hasQueriesParam; - } - - public boolean hasDefaultStatusCodeBinding() { - return functionReturnTypeGenerator.hasDefaultStatusCodeBinding(); - } - - public List getNonDefaultStatusCodes() { - return functionReturnTypeGenerator.getNonDefaultStatusCodes(); - } - - public String getHeadersParamName() { - return headersParamName; + super(operation, openAPI, httpMethod, path); } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java index 27355d889..68cdcf89d 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/parameter/HeadersParameterGenerator.java @@ -2,9 +2,11 @@ import io.ballerina.compiler.syntax.tree.ArrayDimensionNode; import io.ballerina.compiler.syntax.tree.BasicLiteralNode; +import io.ballerina.compiler.syntax.tree.DefaultableParameterNode; import io.ballerina.compiler.syntax.tree.LiteralValueToken; import io.ballerina.compiler.syntax.tree.NodeFactory; import io.ballerina.compiler.syntax.tree.ParameterNode; +import io.ballerina.compiler.syntax.tree.RequiredParameterNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.compiler.syntax.tree.TypeDescriptorNode; import io.ballerina.compiler.syntax.tree.TypeParameterNode; @@ -226,4 +228,15 @@ private Schema getSchemaWithDetails(Parameter parameter) { } return schema; } + + public static String getHeadersParamName(ParameterNode parameterNode) { + if (parameterNode instanceof RequiredParameterNode requiredParameterNode && + requiredParameterNode.paramName().isPresent()) { + return requiredParameterNode.paramName().get().text(); + } else if (parameterNode instanceof DefaultableParameterNode parameter && + parameter.paramName().isPresent()) { + return parameter.paramName().get().text(); + } + return HEADERS; + } } diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java index 2680a46b0..460c330c5 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java @@ -370,22 +370,7 @@ public static String getValidNameForType(String identifier) { if (identifier.isBlank()) { return "\\" + identifier; } - // this - > !identifier.matches("\\b[a-zA-Z][a-zA-Z0-9]*\\b") && - if (!identifier.matches("\\b[0-9]*\\b")) { - String[] split = identifier.split(GeneratorConstants.ESCAPE_PATTERN_FOR_MODIFIER); - StringBuilder validName = new StringBuilder(); - for (String part : split) { - if (!part.isBlank()) { - if (split.length > 1) { - part = part.substring(0, 1).toUpperCase(Locale.ENGLISH) + part.substring(1); - } - validName.append(part); - } - } - identifier = validName.toString(); - } else { - identifier = "Schema" + identifier; - } + identifier = getValidStringFromIdentifier(identifier, "Schema"); return (identifier.substring(0, 1).toUpperCase(Locale.ENGLISH) + identifier.substring(1)).trim(); } @@ -393,21 +378,27 @@ public static String getValidNameForParameter(String identifier) { if (identifier.isBlank()) { return "param"; } + identifier = getValidStringFromIdentifier(identifier, "param"); + return identifier.trim(); + } + + private static String getValidStringFromIdentifier(String identifier, String prefix) { if (!identifier.matches("\\b[0-9]*\\b")) { String[] split = identifier.split(GeneratorConstants.ESCAPE_PATTERN_FOR_MODIFIER); StringBuilder validName = new StringBuilder(); for (String part : split) { if (!part.isBlank()) { + if (split.length > 1) { part = part.substring(0, 1).toUpperCase(Locale.ENGLISH) + part.substring(1); + } validName.append(part); } } - String modifiedName = validName.substring(0, 1).toLowerCase(Locale.ENGLISH) + validName.substring(1); - identifier = split.length > 1 ? modifiedName : identifier; + identifier = validName.toString(); } else { - identifier = "param" + identifier; + identifier = prefix + identifier; } - return identifier.trim(); + return identifier; } public static Map collectParameterNames(List parameters) { From 2f249f0f40e5c119f36029f2246f92986ebcc9ed Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 14:21:40 +0530 Subject: [PATCH 07/13] Make abstract class constructor protected --- .../generators/client/AbstractFunctionSignatureGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java index 74cc4e8f1..e5baaad89 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java @@ -61,7 +61,8 @@ public abstract class AbstractFunctionSignatureGenerator implements FunctionSign private boolean hasHeadersParam = false; private boolean hasQueriesParam = false; - public AbstractFunctionSignatureGenerator(Operation operation, OpenAPI openAPI, String httpMethod, String path) { + protected AbstractFunctionSignatureGenerator(Operation operation, OpenAPI openAPI, String httpMethod, + String path) { this.operation = operation; this.openAPI = openAPI; this.httpMethod = httpMethod; From 54cbf8f981982184878237b30f63a69ce6ea7784 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 14:29:39 +0530 Subject: [PATCH 08/13] Refactor path parameter addition logic --- .../AbstractFunctionSignatureGenerator.java | 16 +++++------ .../RemoteFunctionSignatureGenerator.java | 27 ++++--------------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java index e5baaad89..2a6266aa0 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java @@ -37,6 +37,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import static io.ballerina.compiler.syntax.tree.AbstractNodeFactory.createSeparatedNodeList; @@ -75,7 +76,7 @@ public Optional generateFunctionSignature() { List parameters = operation.getParameters(); ParametersInfo parametersInfo = getParametersInfo(parameters); - if (parametersInfo == null) { + if (Objects.isNull(parametersInfo)) { return Optional.empty(); } @@ -119,11 +120,10 @@ private static List getParameterNodes(ParametersInfo parametersInfo) { } protected ParametersInfo getParametersInfo(List parameters) { - return getParametersInfoWithoutPath(parameters); + return getParametersInfo(parameters, new ArrayList<>()); } - protected ParametersInfo getParametersInfoWithoutPath(List parameters) { - List requiredParams = new ArrayList<>(); + protected ParametersInfo getParametersInfo(List parameters, List requiredParams) { List defaultableParams = new ArrayList<>(); List includedParam = new ArrayList<>(); Token comma = createToken(COMMA_TOKEN); @@ -133,7 +133,7 @@ protected ParametersInfo getParametersInfoWithoutPath(List parameters List pathParameters = new ArrayList<>(); // requestBody - if (operation.getRequestBody() != null) { + if (Objects.nonNull(operation.getRequestBody())) { RequestBodyGenerator requestBodyGenerator = new RequestBodyGenerator(operation.getRequestBody(), openAPI); Optional requestBody = requestBodyGenerator.generateParameterNode(); @@ -147,7 +147,7 @@ protected ParametersInfo getParametersInfoWithoutPath(List parameters } // parameters - query, headers - if (parameters != null) { + if (Objects.nonNull(parameters)) { populateHeaderAndQueryParameters(parameters, queryParameters, headerParameters, pathParameters); List nonHeaderParameters = new ArrayList<>(queryParameters); @@ -198,7 +198,7 @@ protected ParametersInfo getParametersInfoWithoutPath(List parameters } } else { ParameterNode defaultHeaderParam = HeadersParameterGenerator.getDefaultParameterNode().orElse(null); - if (defaultHeaderParam != null) { + if (Objects.nonNull(defaultHeaderParam)) { headersParamName = HeadersParameterGenerator.getHeadersParamName(defaultHeaderParam); hasDefaultHeader = true; hasHeadersParam = true; @@ -212,7 +212,7 @@ protected ParametersInfo getParametersInfoWithoutPath(List parameters private void populateHeaderAndQueryParameters(List parameters, List queryParameters, List headerParameters, List pathParameters) { for (Parameter parameter : parameters) { - if (parameter.get$ref() != null) { + if (Objects.nonNull(parameter.get$ref())) { String paramType = null; try { paramType = extractReferenceType(parameter.get$ref()); diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java index abeb937e1..723a7252d 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/RemoteFunctionSignatureGenerator.java @@ -20,7 +20,6 @@ import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.ParameterNode; -import io.ballerina.compiler.syntax.tree.Token; import io.ballerina.openapi.core.generators.client.parameter.PathParameterGenerator; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -42,27 +41,11 @@ public RemoteFunctionSignatureGenerator(Operation operation, OpenAPI openAPI, St } protected ParametersInfo getParametersInfo(List parameters) { - List requiredParams; - List defaultableParams; - List includedParam; - Token comma = createToken(COMMA_TOKEN); - - ParametersInfo parametersInfo = super.getParametersInfo(parameters); - - if (Objects.isNull(parameters)) { - return parametersInfo; - } - - if (Objects.isNull(parametersInfo)) { - requiredParams = new ArrayList<>(); - defaultableParams = new ArrayList<>(); - includedParam = new ArrayList<>(); - } else { - requiredParams = parametersInfo.requiredParams(); - defaultableParams = parametersInfo.defaultableParams(); - includedParam = parametersInfo.includedParam(); + if (Objects.isNull(parameters)) { + return super.getParametersInfo(null); } + List requiredParams = new ArrayList<>(); // path parameters for (Parameter parameter : parameters) { if (parameter.getIn().equals("path")) { @@ -74,9 +57,9 @@ protected ParametersInfo getParametersInfo(List parameters) { } // Path parameters are always required. requiredParams.add(param.get()); - requiredParams.add(comma); + requiredParams.add(createToken(COMMA_TOKEN)); } } - return new ParametersInfo(requiredParams, defaultableParams, includedParam); + return super.getParametersInfo(parameters, requiredParams); } } From b0e0632a29e0f421b5d59508c0b4c7b2b94a801e Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 15:48:49 +0530 Subject: [PATCH 09/13] Fix sanitization for path params --- .../openapi/core/generators/common/GeneratorUtils.java | 3 --- .../ballerina/openapi/core/generators/common/OASModifier.java | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java index 4a875013d..43e2009cc 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/GeneratorUtils.java @@ -768,9 +768,6 @@ public static OpenAPI normalizeOpenAPI(OpenAPI openAPI, boolean validateOpIds, b if (isSanitized) { OASModifier oasSanitizer = new OASModifier(); Map proposedNameMapping = oasSanitizer.getProposedNameMapping(openAPI); - if (proposedNameMapping.isEmpty()) { - return openAPI; - } return oasSanitizer.modifyWithBallerinaConventions(openAPI, proposedNameMapping); } return openAPI; diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java index 460c330c5..dd4e573e6 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/common/OASModifier.java @@ -379,7 +379,7 @@ public static String getValidNameForParameter(String identifier) { return "param"; } identifier = getValidStringFromIdentifier(identifier, "param"); - return identifier.trim(); + return (identifier.substring(0, 1).toLowerCase(Locale.ENGLISH) + identifier.substring(1)).trim(); } private static String getValidStringFromIdentifier(String identifier, String prefix) { From 0f3db8ff074c7764f04ded65af73694058e1e65a Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 5 Sep 2024 15:48:57 +0530 Subject: [PATCH 10/13] Add test cases --- .../ballerina/openapi/CodeGeneratorTest.java | 52 +++ .../default_headers_conflict_with_query.yaml | 33 ++ .../default_headers_queries_parameters.yaml | 51 +++ .../default_headers_conflict_with_query.bal | 308 ++++++++++++++++ .../default_headers_queries_parameters.bal | 332 ++++++++++++++++++ 5 files changed, 776 insertions(+) create mode 100644 openapi-cli/src/test/resources/default_headers_conflict_with_query.yaml create mode 100644 openapi-cli/src/test/resources/default_headers_queries_parameters.yaml create mode 100644 openapi-cli/src/test/resources/expected_gen/default_headers_conflict_with_query.bal create mode 100644 openapi-cli/src/test/resources/expected_gen/default_headers_queries_parameters.bal diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/CodeGeneratorTest.java b/openapi-cli/src/test/java/io/ballerina/openapi/CodeGeneratorTest.java index 8579493ca..66478a699 100644 --- a/openapi-cli/src/test/java/io/ballerina/openapi/CodeGeneratorTest.java +++ b/openapi-cli/src/test/java/io/ballerina/openapi/CodeGeneratorTest.java @@ -868,6 +868,58 @@ public void testDefaultValueGenerationWithServiceContract() { } } + @Test + public void testDefaultHeadersQueriesParameterNameSanitization() { + String definitionPath = RES_DIR.resolve("default_headers_queries_parameters.yaml").toString(); + BallerinaCodeGenerator generator = new BallerinaCodeGenerator(); + try { + String expectedClientContent = getStringFromGivenBalFile( + expectedDirPath, "default_headers_queries_parameters.bal"); + generator.generateClient(definitionPath, resourcePath.toString(), filter, + new ClientGeneratorOptions(false, true, false, false, + true, false)); + if (Files.exists(resourcePath.resolve("client.bal"))) { + String generatedClient = getStringFromGivenBalFile(resourcePath, "client.bal"); + generatedClient = (generatedClient.trim()).replaceAll("\\s+", ""); + expectedClientContent = (expectedClientContent.trim()).replaceAll("\\s+", ""); + Assert.assertTrue(generatedClient.contains(expectedClientContent)); + } else { + Assert.fail("Client was not generated"); + } + } catch (IOException | BallerinaOpenApiException | + OASTypeGenException | FormatterException e) { + Assert.fail("Error while generating the client: " + e.getMessage()); + } finally { + deleteGeneratedFiles("client.bal"); + } + } + + @Test + public void testDefaultHeadersNameConflictWithQuery() { + String definitionPath = RES_DIR.resolve("default_headers_conflict_with_query.yaml").toString(); + BallerinaCodeGenerator generator = new BallerinaCodeGenerator(); + try { + String expectedClientContent = getStringFromGivenBalFile( + expectedDirPath, "default_headers_conflict_with_query.bal"); + generator.generateClient(definitionPath, resourcePath.toString(), filter, + new ClientGeneratorOptions(false, true, false, false, + true, false)); + if (Files.exists(resourcePath.resolve("client.bal"))) { + String generatedClient = getStringFromGivenBalFile(resourcePath, "client.bal"); + generatedClient = (generatedClient.trim()).replaceAll("\\s+", ""); + expectedClientContent = (expectedClientContent.trim()).replaceAll("\\s+", ""); + Assert.assertTrue(generatedClient.contains(expectedClientContent)); + } else { + Assert.fail("Client was not generated"); + } + } catch (IOException | BallerinaOpenApiException | + OASTypeGenException | FormatterException e) { + Assert.fail("Error while generating the client: " + e.getMessage()); + } finally { + deleteGeneratedFiles("client.bal"); + } + } + private String getStringFromGivenBalFile(Path expectedServiceFile, String s) throws IOException { Stream expectedServiceLines = Files.lines(expectedServiceFile.resolve(s)); diff --git a/openapi-cli/src/test/resources/default_headers_conflict_with_query.yaml b/openapi-cli/src/test/resources/default_headers_conflict_with_query.yaml new file mode 100644 index 000000000..09f8977fc --- /dev/null +++ b/openapi-cli/src/test/resources/default_headers_conflict_with_query.yaml @@ -0,0 +1,33 @@ +openapi: 3.0.1 +info: + title: PayloadV + version: 0.0.0 +servers: + - url: "http://{server}:{port}/payloadV" + variables: + server: + default: localhost + port: + default: "8080" +paths: + /albums/{id}: + get: + operationId: getAlbumsId + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + - name: headers + in: query + schema: + type: string + responses: + "200": + description: Ok + content: + application/json: + schema: + type: object diff --git a/openapi-cli/src/test/resources/default_headers_queries_parameters.yaml b/openapi-cli/src/test/resources/default_headers_queries_parameters.yaml new file mode 100644 index 000000000..3b883b978 --- /dev/null +++ b/openapi-cli/src/test/resources/default_headers_queries_parameters.yaml @@ -0,0 +1,51 @@ +openapi: 3.0.1 +info: + title: PayloadV + version: 0.0.0 +servers: + - url: "http://{server}:{port}/payloadV" + variables: + server: + default: localhost + port: + default: "8080" +paths: + /albums/{id}: + get: + operationId: Get_Albums_Id + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + - name: albumId + in: query + required: false + style: form + explode: true + schema: + type: string + - name: q2 + in: query + required: false + style: form + explode: true + schema: + type: integer + format: int64 + - name: X-HEADER + in: header + required: false + style: simple + explode: false + schema: + type: string + responses: + "200": + description: Ok + content: + application/json: + schema: + type: object diff --git a/openapi-cli/src/test/resources/expected_gen/default_headers_conflict_with_query.bal b/openapi-cli/src/test/resources/expected_gen/default_headers_conflict_with_query.bal new file mode 100644 index 000000000..637f63553 --- /dev/null +++ b/openapi-cli/src/test/resources/expected_gen/default_headers_conflict_with_query.bal @@ -0,0 +1,308 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. +// This file is auto-generated by the Ballerina OpenAPI tool. + +import ballerina/http; +import ballerina/url; + +public isolated client class Client { + final http:Client clientEp; + # Gets invoked to initialize the `connector`. + # + # + config - The configurations to be used when initializing the `connector` + # + serviceUrl - URL of the target service + # + return - An error if connector initialization failed + public isolated function init(ConnectionConfig config = {}, string serviceUrl = "http://localhost:8080/payloadV") returns error? { + http:ClientConfiguration httpClientConfig = {httpVersion: config.httpVersion, timeout: config.timeout, forwarded: config.forwarded, poolConfig: config.poolConfig, compression: config.compression, circuitBreaker: config.circuitBreaker, retryConfig: config.retryConfig, validation: config.validation}; + do { + if config.http1Settings is ClientHttp1Settings { + ClientHttp1Settings settings = check config.http1Settings.ensureType(ClientHttp1Settings); + httpClientConfig.http1Settings = {...settings}; + } + if config.http2Settings is http:ClientHttp2Settings { + httpClientConfig.http2Settings = check config.http2Settings.ensureType(http:ClientHttp2Settings); + } + if config.cache is http:CacheConfig { + httpClientConfig.cache = check config.cache.ensureType(http:CacheConfig); + } + if config.responseLimits is http:ResponseLimitConfigs { + httpClientConfig.responseLimits = check config.responseLimits.ensureType(http:ResponseLimitConfigs); + } + if config.secureSocket is http:ClientSecureSocket { + httpClientConfig.secureSocket = check config.secureSocket.ensureType(http:ClientSecureSocket); + } + if config.proxy is http:ProxyConfig { + httpClientConfig.proxy = check config.proxy.ensureType(http:ProxyConfig); + } + } + http:Client httpEp = check new (serviceUrl, httpClientConfig); + self.clientEp = httpEp; + return; + } + + # + headers - Headers to be sent with the request + # + queries - Queries to be sent with the request + # + return - Ok + resource isolated function get albums/[int id](map headers1 = {}, *GetAlbumsIdQueries queries) returns record {}|error { + string resourcePath = string `/albums/${getEncodedUri(id)}`; + resourcePath = resourcePath + check getPathForQueryParam(queries); + return self.clientEp->get(resourcePath, headers1); + } +} + +type SimpleBasicType string|boolean|int|float|decimal; + +# Represents encoding mechanism details. +type Encoding record { + # Defines how multiple values are delimited + string style = FORM; + # Specifies whether arrays and objects should generate as separate fields + boolean explode = true; + # Specifies the custom content type + string contentType?; + # Specifies the custom headers + map headers?; +}; + +enum EncodingStyle { + DEEPOBJECT, FORM, SPACEDELIMITED, PIPEDELIMITED +} + +final Encoding & readonly defaultEncoding = {}; + +# Serialize the record according to the deepObject style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + return - Serialized record as a string +isolated function getDeepObjectStyleRequest(string parent, record {} anyRecord) returns string { + string[] recordArray = []; + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(parent + "[" + key + "]" + "=" + getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(parent + "[" + key + "]" + "[]", value, DEEPOBJECT, true)); + } else if value is record {} { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getDeepObjectStyleRequest(nextParent, value)); + } else if value is record {}[] { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getSerializedRecordArray(nextParent, value, DEEPOBJECT)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + return string:'join("", ...recordArray); +} + +# Serialize the record according to the form style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getFormStyleRequest(string parent, record {} anyRecord, boolean explode = true) returns string { + string[] recordArray = []; + if explode { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(key, "=", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(key, value, explode = explode)); + } else if value is record {} { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + } else { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(key, ",", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(key, value, explode = false)); + } else if value is record {} { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push(","); + } + _ = recordArray.pop(); + } + return string:'join("", ...recordArray); +} + +# Serialize arrays. +# +# + arrayName - Name of the field with arrays +# + anyArray - Array to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized array as a string +isolated function getSerializedArray(string arrayName, anydata[] anyArray, string style = "form", boolean explode = true) returns string { + string key = arrayName; + string[] arrayValues = []; + if anyArray.length() > 0 { + if style == FORM && !explode { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), ","); + } + } else if style == SPACEDELIMITED && !explode { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "%20"); + } + } else if style == PIPEDELIMITED && !explode { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "|"); + } + } else if style == DEEPOBJECT { + foreach anydata i in anyArray { + arrayValues.push(key, "[]", "=", getEncodedUri(i.toString()), "&"); + } + } else { + foreach anydata i in anyArray { + arrayValues.push(key, "=", getEncodedUri(i.toString()), "&"); + } + } + _ = arrayValues.pop(); + } + return string:'join("", ...arrayValues); +} + +# Serialize the array of records according to the form style. +# +# + parent - Parent record name +# + value - Array of records to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getSerializedRecordArray(string parent, record {}[] value, string style = FORM, boolean explode = true) returns string { + string[] serializedArray = []; + if style == DEEPOBJECT { + int arayIndex = 0; + foreach var recordItem in value { + serializedArray.push(getDeepObjectStyleRequest(parent + "[" + arayIndex.toString() + "]", recordItem), "&"); + arayIndex = arayIndex + 1; + } + } else { + if !explode { + serializedArray.push(parent, "="); + } + foreach var recordItem in value { + serializedArray.push(getFormStyleRequest(parent, recordItem, explode), ","); + } + } + _ = serializedArray.pop(); + return string:'join("", ...serializedArray); +} + +# Get Encoded URI for a given value. +# +# + value - Value to be encoded +# + return - Encoded string +isolated function getEncodedUri(anydata value) returns string { + string|error encoded = url:encode(value.toString(), "UTF8"); + if encoded is string { + return encoded; + } else { + return value.toString(); + } +} + +# Generate query path with query parameter. +# +# + queryParam - Query parameter map +# + encodingMap - Details on serialization mechanism +# + return - Returns generated Path or error at failure of client initialization +isolated function getPathForQueryParam(map queryParam, map encodingMap = {}) returns string|error { + string[] param = []; + if queryParam.length() > 0 { + param.push("?"); + foreach var [key, value] in queryParam.entries() { + if value is () { + _ = queryParam.remove(key); + continue; + } + Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; + if value is SimpleBasicType { + param.push(key, "=", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + param.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); + } else if value is record {} { + if encodingData.style == DEEPOBJECT { + param.push(getDeepObjectStyleRequest(key, value)); + } else { + param.push(getFormStyleRequest(key, value, encodingData.explode)); + } + } else { + param.push(key, "=", value.toString()); + } + param.push("&"); + } + _ = param.pop(); + } + string restOfPath = string:'join("", ...param); + return restOfPath; +} + +# Provides settings related to HTTP/1.x protocol. +public type ClientHttp1Settings record {| + # Specifies whether to reuse a connection for multiple requests + http:KeepAlive keepAlive = http:KEEPALIVE_AUTO; + # The chunking behaviour of the request + http:Chunking chunking = http:CHUNKING_AUTO; + # Proxy server related options + ProxyConfig proxy?; +|}; + +# Proxy server configurations to be used with the HTTP client endpoint. +public type ProxyConfig record {| + # Host name of the proxy server + string host = ""; + # Proxy server port + int port = 0; + # Proxy server username + string userName = ""; + # Proxy server password + @display {label: "", kind: "password"} + string password = ""; +|}; + +# Provides a set of configurations for controlling the behaviours when communicating with a remote HTTP endpoint. +@display {label: "Connection Config"} +public type ConnectionConfig record {| + # The HTTP version understood by the client + http:HttpVersion httpVersion = http:HTTP_2_0; + # Configurations related to HTTP/1.x protocol + ClientHttp1Settings http1Settings?; + # Configurations related to HTTP/2 protocol + http:ClientHttp2Settings http2Settings?; + # The maximum time to wait (in seconds) for a response before closing the connection + decimal timeout = 60; + # The choice of setting `forwarded`/`x-forwarded` header + string forwarded = "disable"; + # Configurations associated with request pooling + http:PoolConfiguration poolConfig?; + # HTTP caching related configurations + http:CacheConfig cache?; + # Specifies the way of handling compression (`accept-encoding`) header + http:Compression compression = http:COMPRESSION_AUTO; + # Configurations associated with the behaviour of the Circuit Breaker + http:CircuitBreakerConfig circuitBreaker?; + # Configurations associated with retrying + http:RetryConfig retryConfig?; + # Configurations associated with inbound response size limits + http:ResponseLimitConfigs responseLimits?; + # SSL/TLS-related options + http:ClientSecureSocket secureSocket?; + # Proxy server related options + http:ProxyConfig proxy?; + # Enables the inbound payload validation functionality which provided by the constraint package. Enabled by default + boolean validation = true; +|}; + +# Represents the Queries record for the operation: getAlbumsId +public type GetAlbumsIdQueries record { + string headers?; +}; diff --git a/openapi-cli/src/test/resources/expected_gen/default_headers_queries_parameters.bal b/openapi-cli/src/test/resources/expected_gen/default_headers_queries_parameters.bal new file mode 100644 index 000000000..c7dc3ec98 --- /dev/null +++ b/openapi-cli/src/test/resources/expected_gen/default_headers_queries_parameters.bal @@ -0,0 +1,332 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. +// This file is auto-generated by the Ballerina OpenAPI tool. + +import ballerina/http; +import ballerina/url; + +public isolated client class Client { + final http:Client clientEp; + # Gets invoked to initialize the `connector`. + # + # + config - The configurations to be used when initializing the `connector` + # + serviceUrl - URL of the target service + # + return - An error if connector initialization failed + public isolated function init(ConnectionConfig config = {}, string serviceUrl = "http://localhost:8080/payloadV") returns error? { + http:ClientConfiguration httpClientConfig = {httpVersion: config.httpVersion, timeout: config.timeout, forwarded: config.forwarded, poolConfig: config.poolConfig, compression: config.compression, circuitBreaker: config.circuitBreaker, retryConfig: config.retryConfig, validation: config.validation}; + do { + if config.http1Settings is ClientHttp1Settings { + ClientHttp1Settings settings = check config.http1Settings.ensureType(ClientHttp1Settings); + httpClientConfig.http1Settings = {...settings}; + } + if config.http2Settings is http:ClientHttp2Settings { + httpClientConfig.http2Settings = check config.http2Settings.ensureType(http:ClientHttp2Settings); + } + if config.cache is http:CacheConfig { + httpClientConfig.cache = check config.cache.ensureType(http:CacheConfig); + } + if config.responseLimits is http:ResponseLimitConfigs { + httpClientConfig.responseLimits = check config.responseLimits.ensureType(http:ResponseLimitConfigs); + } + if config.secureSocket is http:ClientSecureSocket { + httpClientConfig.secureSocket = check config.secureSocket.ensureType(http:ClientSecureSocket); + } + if config.proxy is http:ProxyConfig { + httpClientConfig.proxy = check config.proxy.ensureType(http:ProxyConfig); + } + } + http:Client httpEp = check new (serviceUrl, httpClientConfig); + self.clientEp = httpEp; + return; + } + + # + headers - Headers to be sent with the request + # + queries - Queries to be sent with the request + # + return - Ok + resource isolated function get albums/[int id](GetAlbumsIdHeaders headers = {}, *GetAlbumsIdQueries queries) returns record {}|error { + string resourcePath = string `/albums/${getEncodedUri(id)}`; + resourcePath = resourcePath + check getPathForQueryParam(queries); + map httpHeaders = getMapForHeaders(headers); + return self.clientEp->get(resourcePath, httpHeaders); + } +} + +type SimpleBasicType string|boolean|int|float|decimal; + +# Represents encoding mechanism details. +type Encoding record { + # Defines how multiple values are delimited + string style = FORM; + # Specifies whether arrays and objects should generate as separate fields + boolean explode = true; + # Specifies the custom content type + string contentType?; + # Specifies the custom headers + map headers?; +}; + +enum EncodingStyle { + DEEPOBJECT, FORM, SPACEDELIMITED, PIPEDELIMITED +} + +final Encoding & readonly defaultEncoding = {}; + +# Serialize the record according to the deepObject style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + return - Serialized record as a string +isolated function getDeepObjectStyleRequest(string parent, record {} anyRecord) returns string { + string[] recordArray = []; + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(parent + "[" + key + "]" + "=" + getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(parent + "[" + key + "]" + "[]", value, DEEPOBJECT, true)); + } else if value is record {} { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getDeepObjectStyleRequest(nextParent, value)); + } else if value is record {}[] { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getSerializedRecordArray(nextParent, value, DEEPOBJECT)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + return string:'join("", ...recordArray); +} + +# Serialize the record according to the form style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getFormStyleRequest(string parent, record {} anyRecord, boolean explode = true) returns string { + string[] recordArray = []; + if explode { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(key, "=", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(key, value, explode = explode)); + } else if value is record {} { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + } else { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(key, ",", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(key, value, explode = false)); + } else if value is record {} { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push(","); + } + _ = recordArray.pop(); + } + return string:'join("", ...recordArray); +} + +# Serialize arrays. +# +# + arrayName - Name of the field with arrays +# + anyArray - Array to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized array as a string +isolated function getSerializedArray(string arrayName, anydata[] anyArray, string style = "form", boolean explode = true) returns string { + string key = arrayName; + string[] arrayValues = []; + if anyArray.length() > 0 { + if style == FORM && !explode { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), ","); + } + } else if style == SPACEDELIMITED && !explode { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "%20"); + } + } else if style == PIPEDELIMITED && !explode { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "|"); + } + } else if style == DEEPOBJECT { + foreach anydata i in anyArray { + arrayValues.push(key, "[]", "=", getEncodedUri(i.toString()), "&"); + } + } else { + foreach anydata i in anyArray { + arrayValues.push(key, "=", getEncodedUri(i.toString()), "&"); + } + } + _ = arrayValues.pop(); + } + return string:'join("", ...arrayValues); +} + +# Serialize the array of records according to the form style. +# +# + parent - Parent record name +# + value - Array of records to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getSerializedRecordArray(string parent, record {}[] value, string style = FORM, boolean explode = true) returns string { + string[] serializedArray = []; + if style == DEEPOBJECT { + int arayIndex = 0; + foreach var recordItem in value { + serializedArray.push(getDeepObjectStyleRequest(parent + "[" + arayIndex.toString() + "]", recordItem), "&"); + arayIndex = arayIndex + 1; + } + } else { + if !explode { + serializedArray.push(parent, "="); + } + foreach var recordItem in value { + serializedArray.push(getFormStyleRequest(parent, recordItem, explode), ","); + } + } + _ = serializedArray.pop(); + return string:'join("", ...serializedArray); +} + +# Get Encoded URI for a given value. +# +# + value - Value to be encoded +# + return - Encoded string +isolated function getEncodedUri(anydata value) returns string { + string|error encoded = url:encode(value.toString(), "UTF8"); + if encoded is string { + return encoded; + } else { + return value.toString(); + } +} + +# Generate query path with query parameter. +# +# + queryParam - Query parameter map +# + encodingMap - Details on serialization mechanism +# + return - Returns generated Path or error at failure of client initialization +isolated function getPathForQueryParam(map queryParam, map encodingMap = {}) returns string|error { + string[] param = []; + if queryParam.length() > 0 { + param.push("?"); + foreach var [key, value] in queryParam.entries() { + if value is () { + _ = queryParam.remove(key); + continue; + } + Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; + if value is SimpleBasicType { + param.push(key, "=", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + param.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); + } else if value is record {} { + if encodingData.style == DEEPOBJECT { + param.push(getDeepObjectStyleRequest(key, value)); + } else { + param.push(getFormStyleRequest(key, value, encodingData.explode)); + } + } else { + param.push(key, "=", value.toString()); + } + param.push("&"); + } + _ = param.pop(); + } + string restOfPath = string:'join("", ...param); + return restOfPath; +} + +# Generate header map for given header values. +# +# + headerParam - Headers map +# + return - Returns generated map or error at failure of client initialization +isolated function getMapForHeaders(map headerParam) returns map { + map headerMap = {}; + foreach var [key, value] in headerParam.entries() { + if value is SimpleBasicType[] { + headerMap[key] = from SimpleBasicType data in value + select data.toString(); + } else { + headerMap[key] = value.toString(); + } + } + return headerMap; +} + +# Provides settings related to HTTP/1.x protocol. +public type ClientHttp1Settings record {| + # Specifies whether to reuse a connection for multiple requests + http:KeepAlive keepAlive = http:KEEPALIVE_AUTO; + # The chunking behaviour of the request + http:Chunking chunking = http:CHUNKING_AUTO; + # Proxy server related options + ProxyConfig proxy?; +|}; + +# Represents the Headers record for the operation: Get_Albums_Id +public type GetAlbumsIdHeaders record { + string X\-HEADER?; +}; + +# Proxy server configurations to be used with the HTTP client endpoint. +public type ProxyConfig record {| + # Host name of the proxy server + string host = ""; + # Proxy server port + int port = 0; + # Proxy server username + string userName = ""; + # Proxy server password + @display {label: "", kind: "password"} + string password = ""; +|}; + +# Provides a set of configurations for controlling the behaviours when communicating with a remote HTTP endpoint. +@display {label: "Connection Config"} +public type ConnectionConfig record {| + # The HTTP version understood by the client + http:HttpVersion httpVersion = http:HTTP_2_0; + # Configurations related to HTTP/1.x protocol + ClientHttp1Settings http1Settings?; + # Configurations related to HTTP/2 protocol + http:ClientHttp2Settings http2Settings?; + # The maximum time to wait (in seconds) for a response before closing the connection + decimal timeout = 60; + # The choice of setting `forwarded`/`x-forwarded` header + string forwarded = "disable"; + # Configurations associated with request pooling + http:PoolConfiguration poolConfig?; + # HTTP caching related configurations + http:CacheConfig cache?; + # Specifies the way of handling compression (`accept-encoding`) header + http:Compression compression = http:COMPRESSION_AUTO; + # Configurations associated with the behaviour of the Circuit Breaker + http:CircuitBreakerConfig circuitBreaker?; + # Configurations associated with retrying + http:RetryConfig retryConfig?; + # Configurations associated with inbound response size limits + http:ResponseLimitConfigs responseLimits?; + # SSL/TLS-related options + http:ClientSecureSocket secureSocket?; + # Proxy server related options + http:ProxyConfig proxy?; + # Enables the inbound payload validation functionality which provided by the constraint package. Enabled by default + boolean validation = true; +|}; + +# Represents the Queries record for the operation: Get_Albums_Id +public type GetAlbumsIdQueries record { + int q2?; + string albumId?; +}; From 8699389370672bdcadf673bc5392408722e1e9ba Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 6 Sep 2024 08:10:35 +0530 Subject: [PATCH 11/13] Add java doc comment for the class --- .../client/AbstractFunctionSignatureGenerator.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java index 2a6266aa0..016e216dd 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java @@ -49,6 +49,12 @@ import static io.ballerina.openapi.core.generators.common.GeneratorConstants.HEADERS; import static io.ballerina.openapi.core.generators.common.GeneratorUtils.extractReferenceType; +/** + * This class represents the abstract function signature generator which is used to implement + * the common functionalities of the function signature generators. + * + * @since 2.1.1 + */ public abstract class AbstractFunctionSignatureGenerator implements FunctionSignatureGenerator { OpenAPI openAPI; Operation operation; From a25606bf532fa022f92f7bd1256dc6cdeb21d9cf Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 6 Sep 2024 09:55:36 +0530 Subject: [PATCH 12/13] Add suggestion from review --- .../generators/client/AbstractFunctionSignatureGenerator.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java index 016e216dd..becc6d453 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java @@ -93,9 +93,6 @@ public Optional generateFunctionSignature() { FunctionReturnTypeGeneratorImp functionReturnType = getFunctionReturnTypeGenerator(); Optional returnType = functionReturnType.getReturnType(); diagnostics.addAll(functionReturnType.getDiagnostics()); - if (returnType.isEmpty()) { - return Optional.empty(); - } //create function signature node return returnType.map(returnTypeDescriptorNode -> NodeFactory.createFunctionSignatureNode( From 9a0e2dec2b3016265b6c59cd03e12fb06eeec91b Mon Sep 17 00:00:00 2001 From: Krishnananthalingam Tharmigan <63336800+TharmiganK@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:46:11 +0530 Subject: [PATCH 13/13] Update openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java Co-authored-by: Sumudu Nissanka --- .../generators/client/AbstractFunctionSignatureGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java index becc6d453..77d7ea95a 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/generators/client/AbstractFunctionSignatureGenerator.java @@ -53,7 +53,7 @@ * This class represents the abstract function signature generator which is used to implement * the common functionalities of the function signature generators. * - * @since 2.1.1 + * @since 2.2.0 */ public abstract class AbstractFunctionSignatureGenerator implements FunctionSignatureGenerator { OpenAPI openAPI;