From c797d7a434a048b2059c22ef3a3212326bedeb9f Mon Sep 17 00:00:00 2001 From: sbansla Date: Tue, 28 Oct 2025 14:37:43 +0530 Subject: [PATCH 1/9] created constant to check api standard version --- .../twilio/oai/TwilioJavaGeneratorModern.java | 5 ++ .../oai/common/ApplicationConstants.java | 3 +- .../com/twilio/oai/java/JavaApiResource.java | 3 +- .../twilio/oai/java/cache/ResourceCache2.java | 4 ++ .../JsonMultipleResponseProcessor.java | 52 +++++++++++++++++++ .../responsebody/JsonResponseProcessor.java | 3 +- .../ResponseProcessorFactory.java | 1 + 7 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/twilio/oai/java/processor/responsebody/JsonMultipleResponseProcessor.java diff --git a/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java b/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java index 5cced9f22..3fad82dea 100644 --- a/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java +++ b/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableMap; import com.samskivert.mustache.Mustache.Lambda; +import com.twilio.oai.common.ApplicationConstants; import com.twilio.oai.common.EnumConstants; import com.twilio.oai.common.Utility; import com.twilio.oai.java.JavaApiResource; @@ -22,6 +23,7 @@ import org.openapitools.codegen.model.OperationsMap; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -64,6 +66,9 @@ public void processOpts() { // Run once per spec @Override public void processOpenAPI(final OpenAPI openAPI) { + String apiStdVersion = (String)((LinkedHashMap)openAPI.getInfo().getExtensions().get("x-twilio")).get("apiStandards"); + boolean isV1 = ApplicationConstants.isV1.test(apiStdVersion); + ResourceCacheContext.get().setV1(isV1); String domain = twilioCodegen.getDomainFromOpenAPI(openAPI); String version = twilioCodegen.getVersionFromOpenAPI(openAPI); twilioCodegen.setDomain(domain); diff --git a/src/main/java/com/twilio/oai/common/ApplicationConstants.java b/src/main/java/com/twilio/oai/common/ApplicationConstants.java index eee6757df..ba5c08dd5 100644 --- a/src/main/java/com/twilio/oai/common/ApplicationConstants.java +++ b/src/main/java/com/twilio/oai/common/ApplicationConstants.java @@ -65,7 +65,6 @@ public class ApplicationConstants { public static final String X_MODEL_TYPE = "x-model-type"; // EnumConstants.OpenApiEnumType public static final String X_IS_MODEL = "x-is-model"; public static final String X_REQUEST_CONTENT_TYPE = "x-request-content-type"; - - + public static final Predicate isV1 = input -> input != null && input.startsWith("v1"); // Usage: isV1.test("v1.0"); } diff --git a/src/main/java/com/twilio/oai/java/JavaApiResource.java b/src/main/java/com/twilio/oai/java/JavaApiResource.java index 392dc06e8..c4ff979f3 100644 --- a/src/main/java/com/twilio/oai/java/JavaApiResource.java +++ b/src/main/java/com/twilio/oai/java/JavaApiResource.java @@ -18,8 +18,8 @@ public class JavaApiResource { List operations; Set response; String namespaceSubPart; - Boolean responseFlag = null; // true or NUll + Boolean isApiV1 = null; // true or NUll public JavaApiResource(JavaApiResourceBuilder builder) { resourceName = ResourceCacheContext.get().getResourceName(); @@ -30,6 +30,7 @@ public JavaApiResource(JavaApiResourceBuilder builder) { this.response = ResourceCacheContext.get().getResponse(); if (response != null && !response.isEmpty()) responseFlag = true; this.namespaceSubPart = builder.namespaceSubPart; + if (ResourceCacheContext.get().isV1()) isApiV1 = true; } } diff --git a/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java b/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java index 5aaef466d..3cb86ecb5 100644 --- a/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java +++ b/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java @@ -31,6 +31,10 @@ public class ResourceCache2 { @Getter private Set enumsClassesForMustache = new HashSet<>(); + + @Getter + @Setter + private boolean isV1; public void setAllModelsByDefaultGenerator(ArrayList allModelsByDefaultGenerator) { this.allModelsByDefaultGenerator = new ArrayList<>(allModelsByDefaultGenerator); diff --git a/src/main/java/com/twilio/oai/java/processor/responsebody/JsonMultipleResponseProcessor.java b/src/main/java/com/twilio/oai/java/processor/responsebody/JsonMultipleResponseProcessor.java new file mode 100644 index 000000000..279819287 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/responsebody/JsonMultipleResponseProcessor.java @@ -0,0 +1,52 @@ +package com.twilio.oai.java.processor.responsebody; + +import com.twilio.oai.common.ApplicationConstants; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.format.Deserializer; +import com.twilio.oai.java.processor.enums.EnumProcessorFactory; +import com.twilio.oai.java.processor.requestbody.RecursiveModelProcessor; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; + +import java.util.Map; + +public class JsonMultipleResponseProcessor implements ResponseProcessor { + EnumProcessorFactory enumProcessorFactory = EnumProcessorFactory.getInstance(); + RecursiveModelProcessor recursiveModelProcessor = new RecursiveModelProcessor(); + @Override + public void process(final CodegenOperation codegenOperation) { + /* There are 5 types of operation we are supporting. + * delete -- does not have response body + * fetch, create, update --> have body + * list --> has pagination and body + */ + if (codegenOperation.operationId.toLowerCase().startsWith("delete")) return; + + } + + public boolean shouldProcess(final CodegenOperation codegenOperation) { + if (!ResourceCacheContext.get().isV1()) return false; + + if (codegenOperation.produces != null && !codegenOperation.produces.isEmpty()) { + for (Map contentType : codegenOperation.produces) { + if (getContentType().equals(contentType.get("mediaType")) || "application/scim+json".equals(contentType.get("mediaType"))) { + return true; + } + } + } + return false; + } + + private void processResponseWithoutPagination() { + + } + + private void processResponseWithPagination() { + + } + + @Override + public String getContentType() { + return "application/json"; + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java b/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java index 9ab982846..ccad09ece 100644 --- a/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java +++ b/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java @@ -57,7 +57,8 @@ private CodegenModel getModelFromListOperation(CodegenModel codegenModel) { } public boolean shouldProcess(final CodegenOperation codegenOperation) { - System.out.println(codegenOperation.operationId); + if (ResourceCacheContext.get().isV1()) return false; + if (codegenOperation.produces != null && !codegenOperation.produces.isEmpty()) { for (Map contentType : codegenOperation.produces) { if (getContentType().equals(contentType.get("mediaType")) || "application/scim+json".equals(contentType.get("mediaType"))) { diff --git a/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java b/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java index d67553649..3f02b2b06 100644 --- a/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java +++ b/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java @@ -11,6 +11,7 @@ public class ResponseProcessorFactory { private ResponseProcessorFactory() { processors.add(new JsonResponseProcessor()); + processors.add(new JsonMultipleResponseProcessor()); } public static ResponseProcessorFactory getInstance() { From d697fbe97f234beeda4968ef18c55f66801f069a Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 4 Nov 2025 13:34:55 +0530 Subject: [PATCH 2/9] chore: Twilio API Standard v1.0 --- .../common/operationMethod.mustache | 37 +++++++++++------ .../creator/operationMethod.mustache | 37 +++++++++++------ .../deleter/operationMethod.mustache | 37 +++++++++++------ .../fetcher/operationMethod.mustache | 41 ++++++++++++------- .../reader/operationMethod.mustache | 29 +++++++++---- .../updater/operationMethod.mustache | 37 +++++++++++------ 6 files changed, 142 insertions(+), 76 deletions(-) diff --git a/src/main/resources/twilio-java/common/operationMethod.mustache b/src/main/resources/twilio-java/common/operationMethod.mustache index c518e5cba..f50e3c196 100644 --- a/src/main/resources/twilio-java/common/operationMethod.mustache +++ b/src/main/resources/twilio-java/common/operationMethod.mustache @@ -1,6 +1,6 @@ -{{! +{{! resourceName: Api Name as identified by Directory Structure service -x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 httpMethod: http method associated in the current operation. @@ -10,7 +10,7 @@ vendorExtensions.x-content-type: content type of the request, example: applicati @Override public {{resourceName}} {{vendorExtensions.x-common-action-method}}(final TwilioRestClient client) { {{>common/generateUri}} - + Request request = new Request( HttpMethod.{{httpMethod}}, Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), @@ -31,21 +31,32 @@ vendorExtensions.x-content-type: content type of the request, example: applicati {{#bodyParams.0}} addPostParams(request, client); {{/bodyParams.0}} - + Response response = client.request(request); - + if (response == null) { throw new ApiConnectionException("{{resourceName}} creation failed: Unable to connect to server"); - } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( - response.getStream(), - client.getObjectMapper() - ); + response.getStream(), + client.getObjectMapper()); + if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); + throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } - + } {{! end of else if }}{{/isV1}} + {{#isV1}} + else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestExceptionV10 restException = RestExceptionV10.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + {{/isV1}} + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); - } \ No newline at end of file + } diff --git a/src/main/resources/twilio-java/creator/operationMethod.mustache b/src/main/resources/twilio-java/creator/operationMethod.mustache index 32496cede..49ca1e5d9 100644 --- a/src/main/resources/twilio-java/creator/operationMethod.mustache +++ b/src/main/resources/twilio-java/creator/operationMethod.mustache @@ -1,6 +1,6 @@ -{{! +{{! resourceName: Api Name as identified by Directory Structure service -x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 httpMethod: http method associated in the current operation. @@ -10,7 +10,7 @@ vendorExtensions.x-content-type: content type of the request, example: applicati @Override public {{resourceName}} {{vendorExtensions.x-common-action-method}}(final TwilioRestClient client) { {{>common/generateUri}} - + Request request = new Request( HttpMethod.{{httpMethod}}, Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), @@ -34,21 +34,32 @@ vendorExtensions.x-content-type: content type of the request, example: applicati {{#bodyParams.0}} addPostParams(request, client); {{/bodyParams.0}} - + Response response = client.request(request); - + if (response == null) { throw new ApiConnectionException("{{resourceName}} creation failed: Unable to connect to server"); - } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( - response.getStream(), - client.getObjectMapper() - ); + response.getStream(), + client.getObjectMapper()); + if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); + throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } - + } {{! end of else if }}{{/isV1}} + {{#isV1}} + else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestExceptionV10 restException = RestExceptionV10.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + {{/isV1}} + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); - } \ No newline at end of file + } diff --git a/src/main/resources/twilio-java/deleter/operationMethod.mustache b/src/main/resources/twilio-java/deleter/operationMethod.mustache index ba98e2ba1..ccb8f2f13 100644 --- a/src/main/resources/twilio-java/deleter/operationMethod.mustache +++ b/src/main/resources/twilio-java/deleter/operationMethod.mustache @@ -1,6 +1,6 @@ -{{! +{{! resourceName: Api Name as identified by Directory Structure service -x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 httpMethod: http method associated in the current operation. @@ -10,7 +10,7 @@ vendorExtensions.x-content-type: content type of the request, example: applicati @Override public boolean delete(final TwilioRestClient client) { {{>common/generateUri}} - + Request request = new Request( HttpMethod.{{httpMethod}}, Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), @@ -28,20 +28,31 @@ vendorExtensions.x-content-type: content type of the request, example: applicati {{#headerParams.0}} addHeaderParams(request); {{/headerParams.0}} - + Response response = client.request(request); - + if (response == null) { throw new ApiConnectionException("{{resourceName}} delete failed: Unable to connect to server"); - } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson( - response.getStream(), - client.getObjectMapper() - ); + } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } {{! end of else if }}{{/isV1}} + {{#isV1}} + else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestExceptionV10 restException = RestExceptionV10.fromJson( + response.getStream(), + client.getObjectMapper()); + if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); + throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } + {{/isV1}} return response.getStatusCode() == 204; - } \ No newline at end of file + } diff --git a/src/main/resources/twilio-java/fetcher/operationMethod.mustache b/src/main/resources/twilio-java/fetcher/operationMethod.mustache index 8ead0de7b..6179da3e2 100644 --- a/src/main/resources/twilio-java/fetcher/operationMethod.mustache +++ b/src/main/resources/twilio-java/fetcher/operationMethod.mustache @@ -1,6 +1,6 @@ -{{! +{{! resourceName: Api Name as identified by Directory Structure service -x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 httpMethod: http method associated in the current operation. @@ -10,7 +10,7 @@ vendorExtensions.x-content-type: content type of the request, example: applicati @Override public {{resourceName}} fetch(final TwilioRestClient client) { {{>common/generateUri}} - + Request request = new Request( HttpMethod.{{httpMethod}}, Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), @@ -28,20 +28,31 @@ vendorExtensions.x-content-type: content type of the request, example: applicati {{#headerParams.0}} addHeaderParams(request); {{/headerParams.0}} - + Response response = client.request(request); - + if (response == null) { throw new ApiConnectionException("{{resourceName}} fetch failed: Unable to connect to server"); - } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson( - response.getStream(), - client.getObjectMapper() - ); - if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); - } - throw new ApiException(restException); + } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); } + throw new ApiException(restException); + } {{! end of else if }}{{/isV1}} + {{#isV1}} + else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestExceptionV10 restException = RestExceptionV10.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + {{/isV1}} return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); - } \ No newline at end of file + } diff --git a/src/main/resources/twilio-java/reader/operationMethod.mustache b/src/main/resources/twilio-java/reader/operationMethod.mustache index 7dea9b5d8..88f81b6e3 100644 --- a/src/main/resources/twilio-java/reader/operationMethod.mustache +++ b/src/main/resources/twilio-java/reader/operationMethod.mustache @@ -1,6 +1,6 @@ -{{! +{{! resourceName: Api Name as identified by Directory Structure service -recordKey: +recordKey: httpMethod: http method associated in the current operation. domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java }} @@ -8,7 +8,7 @@ domainName: example api, video, chat, etc. These can be found in Domains.java in public ResourceSet<{{resourceName}}> read(final TwilioRestClient client) { return new ResourceSet<>(this, client, firstPage(client)); } - + public Page<{{resourceName}}> firstPage(final TwilioRestClient client) { {{>common/generateUri}} Request request = new Request( @@ -33,16 +33,27 @@ domainName: example api, video, chat, etc. These can be found in Domains.java in Response response = client.request(request); if (response == null) { throw new ApiConnectionException("{{resourceName}} read failed: Unable to connect to server"); - } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - + if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }} + } {{! end of else if }}{{/isV1}} + {{#isV1}} + else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestExceptionV10 restException = RestExceptionV10.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + {{/isV1}} return Page.fromJson( "{{recordKey}}", @@ -60,11 +71,11 @@ domainName: example api, video, chat, etc. These can be found in Domains.java in @Override public Page<{{resourceName}}> nextPage(final Page<{{resourceName}}> page, final TwilioRestClient client) { Request request = new Request(HttpMethod.GET, page.getNextPageUrl(Domains.API.toString())); - return pageForRequest(client, request); + return pageForRequest(client, request); } @Override public Page<{{resourceName}}> getPage(final String targetUrl, final TwilioRestClient client) { Request request = new Request(HttpMethod.GET, targetUrl); - return pageForRequest(client, request); - } \ No newline at end of file + return pageForRequest(client, request); + } diff --git a/src/main/resources/twilio-java/updater/operationMethod.mustache b/src/main/resources/twilio-java/updater/operationMethod.mustache index 6744cbbc4..f2662f86a 100644 --- a/src/main/resources/twilio-java/updater/operationMethod.mustache +++ b/src/main/resources/twilio-java/updater/operationMethod.mustache @@ -1,6 +1,6 @@ -{{! +{{! resourceName: Api Name as identified by Directory Structure service -x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 httpMethod: http method associated in the current operation. @@ -10,7 +10,7 @@ vendorExtensions.x-content-type: content type of the request, example: applicati @Override public {{resourceName}} {{vendorExtensions.x-common-action-method}}(final TwilioRestClient client) { {{>common/generateUri}} - + Request request = new Request( HttpMethod.{{httpMethod}}, Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), @@ -34,21 +34,32 @@ vendorExtensions.x-content-type: content type of the request, example: applicati {{#bodyParams.0}} addPostParams(request, client); {{/bodyParams.0}} - + Response response = client.request(request); - + if (response == null) { throw new ApiConnectionException("{{resourceName}} update failed: Unable to connect to server"); - } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( - response.getStream(), - client.getObjectMapper() - ); + response.getStream(), + client.getObjectMapper()); + if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); + throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } - + } {{! end of else if }}{{/isV1}} + {{#isV1}} + else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestExceptionV10 restException = RestExceptionV10.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + {{/isV1}} + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); - } \ No newline at end of file + } From 30287d04c618c19355d0ba503f23d7b9cfbb2a8c Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 5 Nov 2025 19:06:08 +0530 Subject: [PATCH 3/9] chore: Twilio API Standard v1.0 --- examples/test_spec/twilio_pagination_v1.yaml | 95 +++++++++++++++++++ .../twilio/oai/TwilioJavaGeneratorModern.java | 6 +- .../common/operationMethod.mustache | 10 +- .../creator/operationMethod.mustache | 10 +- .../deleter/operationMethod.mustache | 10 +- .../fetcher/operationMethod.mustache | 10 +- .../reader/operationMethod.mustache | 10 +- .../updater/operationMethod.mustache | 10 +- .../com/twilio/oai/TwilioGeneratorTest.java | 2 +- 9 files changed, 125 insertions(+), 38 deletions(-) create mode 100644 examples/test_spec/twilio_pagination_v1.yaml diff --git a/examples/test_spec/twilio_pagination_v1.yaml b/examples/test_spec/twilio_pagination_v1.yaml new file mode 100644 index 000000000..fd929f372 --- /dev/null +++ b/examples/test_spec/twilio_pagination_v1.yaml @@ -0,0 +1,95 @@ +# This spec tests the token pagination strategy as per Twilio API Standards V1.0 + +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - REQUEST BODY TEST + version: 1.11.0 + x-twilio: + apiStandards: v1.0 +openapi: 3.0.1 + +components: + securitySchemes: + accountSid_authToken: + scheme: basic + type: http + schemas: + SampleResponseObject: + type: object + properties: + id: + type: string + name: + type: string +paths: + /v2/Services: + servers: + - url: https://testparameter.twilio.com + get: + operationId: ListService + description: Retrieve a list of all Services + parameters: + - name: pageSize + in: query + description: Maximum number of items to return in a single response + required: false + schema: + type: integer + minimum: 1 + maximum: 1000 + example: 50 + - name: pageToken + in: query + description: A URL-safe, base64-encoded token representing the page of results to return + required: false + schema: + type: string + example: "eyJwYWdlIjoyLCJxdWVyeSI6ImJvb2tzIn0=" + security: + - accountSid_authToken: [ ] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + required: + - services + - meta + properties: + services: + type: array + minItems: 0 + items: + $ref: '#/components/schemas/SampleResponseObject' + meta: + type: object + required: + - key + - pageSize + properties: + key: + type: string + description: The key of the list property contains the actual data items + example: "services" + pageSize: + type: integer + description: The actual number of items returned in this response + example: 20 + previousToken: + type: string + description: Token to fetch the previous page of results + example: "eyJwYWdlIjowLCJxdWVyeSI6ImJvb2tzIn0=" + nextToken: + type: string + description: Token to fetch the next page of results + example: "eyJwYWdlIjoyLCJxdWVyeSI6ImJvb2tzIn0=" diff --git a/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java b/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java index 3fad82dea..53336fdc0 100644 --- a/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java +++ b/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java @@ -16,6 +16,7 @@ import com.twilio.oai.templating.mustache.ReplaceHyphenLambda; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.Schema; +import java.util.Optional; import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.languages.JavaClientCodegen; import org.openapitools.codegen.model.ModelMap; @@ -66,7 +67,10 @@ public void processOpts() { // Run once per spec @Override public void processOpenAPI(final OpenAPI openAPI) { - String apiStdVersion = (String)((LinkedHashMap)openAPI.getInfo().getExtensions().get("x-twilio")).get("apiStandards"); + Optional apiStdVersionOpt = openAPI.getInfo().getExtensions() != null ? + Optional.ofNullable((String)((LinkedHashMap)openAPI.getInfo().getExtensions().get("x-twilio")).get("apiStandards")) + : Optional.empty(); + String apiStdVersion = apiStdVersionOpt.orElse("unknown"); boolean isV1 = ApplicationConstants.isV1.test(apiStdVersion); ResourceCacheContext.get().setV1(isV1); String domain = twilioCodegen.getDomainFromOpenAPI(openAPI); diff --git a/src/main/resources/twilio-java/common/operationMethod.mustache b/src/main/resources/twilio-java/common/operationMethod.mustache index f50e3c196..9cf0e6037 100644 --- a/src/main/resources/twilio-java/common/operationMethod.mustache +++ b/src/main/resources/twilio-java/common/operationMethod.mustache @@ -36,27 +36,25 @@ vendorExtensions.x-content-type: content type of the request, example: applicati if (response == null) { throw new ApiConnectionException("{{resourceName}} creation failed: Unable to connect to server"); - } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isApiV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }}{{/isV1}} - {{#isV1}} + } {{! end of else if }}{{/isApiV1}} + {{#isApiV1}} else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestExceptionV10 restException = RestExceptionV10.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - {{/isV1}} + {{/isApiV1}} return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); } diff --git a/src/main/resources/twilio-java/creator/operationMethod.mustache b/src/main/resources/twilio-java/creator/operationMethod.mustache index 49ca1e5d9..0cf6a5b77 100644 --- a/src/main/resources/twilio-java/creator/operationMethod.mustache +++ b/src/main/resources/twilio-java/creator/operationMethod.mustache @@ -39,27 +39,25 @@ vendorExtensions.x-content-type: content type of the request, example: applicati if (response == null) { throw new ApiConnectionException("{{resourceName}} creation failed: Unable to connect to server"); - } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isApiV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }}{{/isV1}} - {{#isV1}} + } {{! end of else if }}{{/isApiV1}} + {{#isApiV1}} else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestExceptionV10 restException = RestExceptionV10.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - {{/isV1}} + {{/isApiV1}} return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); } diff --git a/src/main/resources/twilio-java/deleter/operationMethod.mustache b/src/main/resources/twilio-java/deleter/operationMethod.mustache index ccb8f2f13..a536a7ac6 100644 --- a/src/main/resources/twilio-java/deleter/operationMethod.mustache +++ b/src/main/resources/twilio-java/deleter/operationMethod.mustache @@ -33,26 +33,24 @@ vendorExtensions.x-content-type: content type of the request, example: applicati if (response == null) { throw new ApiConnectionException("{{resourceName}} delete failed: Unable to connect to server"); - } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isApiV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }}{{/isV1}} - {{#isV1}} + } {{! end of else if }}{{/isApiV1}} + {{#isApiV1}} else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestExceptionV10 restException = RestExceptionV10.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - {{/isV1}} + {{/isApiV1}} return response.getStatusCode() == 204; } diff --git a/src/main/resources/twilio-java/fetcher/operationMethod.mustache b/src/main/resources/twilio-java/fetcher/operationMethod.mustache index 6179da3e2..9396e4037 100644 --- a/src/main/resources/twilio-java/fetcher/operationMethod.mustache +++ b/src/main/resources/twilio-java/fetcher/operationMethod.mustache @@ -33,26 +33,24 @@ vendorExtensions.x-content-type: content type of the request, example: applicati if (response == null) { throw new ApiConnectionException("{{resourceName}} fetch failed: Unable to connect to server"); - } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isApiV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }}{{/isV1}} - {{#isV1}} + } {{! end of else if }}{{/isApiV1}} + {{#isApiV1}} else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestExceptionV10 restException = RestExceptionV10.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - {{/isV1}} + {{/isApiV1}} return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); } diff --git a/src/main/resources/twilio-java/reader/operationMethod.mustache b/src/main/resources/twilio-java/reader/operationMethod.mustache index 88f81b6e3..ecdb62bd7 100644 --- a/src/main/resources/twilio-java/reader/operationMethod.mustache +++ b/src/main/resources/twilio-java/reader/operationMethod.mustache @@ -33,27 +33,25 @@ domainName: example api, video, chat, etc. These can be found in Domains.java in Response response = client.request(request); if (response == null) { throw new ApiConnectionException("{{resourceName}} read failed: Unable to connect to server"); - } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isApiV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }}{{/isV1}} - {{#isV1}} + } {{! end of else if }}{{/isApiV1}} + {{#isApiV1}} else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestExceptionV10 restException = RestExceptionV10.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - {{/isV1}} + {{/isApiV1}} return Page.fromJson( "{{recordKey}}", diff --git a/src/main/resources/twilio-java/updater/operationMethod.mustache b/src/main/resources/twilio-java/updater/operationMethod.mustache index f2662f86a..b7244d254 100644 --- a/src/main/resources/twilio-java/updater/operationMethod.mustache +++ b/src/main/resources/twilio-java/updater/operationMethod.mustache @@ -39,27 +39,25 @@ vendorExtensions.x-content-type: content type of the request, example: applicati if (response == null) { throw new ApiConnectionException("{{resourceName}} update failed: Unable to connect to server"); - } {{^isV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + } {{^isApiV1}}else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestException restException = RestException.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - } {{! end of else if }}{{/isV1}} - {{#isV1}} + } {{! end of else if }}{{/isApiV1}} + {{#isApiV1}} else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { RestExceptionV10 restException = RestExceptionV10.fromJson( response.getStream(), client.getObjectMapper()); - if (restException == null) { throw new ApiException("Server Error, no content", response.getStatusCode()); } throw new ApiException(restException); - {{/isV1}} + {{/isApiV1}} return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); } diff --git a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java index f8cb7b80e..8c6349b0d 100644 --- a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java +++ b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java @@ -40,7 +40,7 @@ public static void setUp() { @Test public void launchGenerator() { - final String pathname = "examples/spec/twilio_flex_v1.yaml"; + final String pathname = "/Users/manisingh/github/twilio/twilio-oai-generator/examples/test_spec/twilio_pagination_v1.yaml"; File filesList[] ; File directoryPath = new File(pathname); if (directoryPath.isDirectory()) { From 0a57b1275484d4c1cbc4bd9ac49ced3ac6ab8e5f Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 5 Nov 2025 19:12:28 +0530 Subject: [PATCH 4/9] chore: Twilio API Standard v1.0 --- src/test/java/com/twilio/oai/TwilioGeneratorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java index 8c6349b0d..ff2cf8c1a 100644 --- a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java +++ b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java @@ -40,7 +40,7 @@ public static void setUp() { @Test public void launchGenerator() { - final String pathname = "/Users/manisingh/github/twilio/twilio-oai-generator/examples/test_spec/twilio_pagination_v1.yaml"; + final String pathname = "examples/test_spec/twilio_pagination_v1.yaml"; File filesList[] ; File directoryPath = new File(pathname); if (directoryPath.isDirectory()) { From b3b4acf29c6adb415aca2d4d94fb1953173ba04c Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 5 Nov 2025 19:26:13 +0530 Subject: [PATCH 5/9] chore: Twilio API Standard v1.0 --- examples/java/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/java/Dockerfile b/examples/java/Dockerfile index 61cfaa6d7..0214d2a4f 100644 --- a/examples/java/Dockerfile +++ b/examples/java/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8 +FROM openjdk:8-jdk RUN apt-get update && apt-get install maven -y From d6630a83fb2fa4eef162d815e395f0f3880daf9b Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 5 Nov 2025 19:29:14 +0530 Subject: [PATCH 6/9] chore: Twilio API Standard v1.0 --- examples/java/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/java/Dockerfile b/examples/java/Dockerfile index 0214d2a4f..58ac47ebe 100644 --- a/examples/java/Dockerfile +++ b/examples/java/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8-jdk +FROM openjdk:8u102-jre RUN apt-get update && apt-get install maven -y From 0a96e4d24d86692672bab0c87abd3e3882aa0965 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 5 Nov 2025 19:37:15 +0530 Subject: [PATCH 7/9] chore: Twilio API Standard v1.0 --- examples/java/Dockerfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/java/Dockerfile b/examples/java/Dockerfile index 58ac47ebe..64297415f 100644 --- a/examples/java/Dockerfile +++ b/examples/java/Dockerfile @@ -1,6 +1,10 @@ -FROM openjdk:8u102-jre +FROM eclipse-temurin:11-jre -RUN apt-get update && apt-get install maven -y +# Install Maven with proper error handling +RUN apt-get update && \ + apt-get install -y --no-install-recommends maven && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* WORKDIR /app RUN git clone https://github.com/twilio/twilio-java.git From cfa13b5e288d47e07da8f41b9976f76a63505111 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 5 Nov 2025 19:47:05 +0530 Subject: [PATCH 8/9] chore: Twilio API Standard v1.0 --- examples/java/Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/java/Dockerfile b/examples/java/Dockerfile index 64297415f..c413e7997 100644 --- a/examples/java/Dockerfile +++ b/examples/java/Dockerfile @@ -7,6 +7,13 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* WORKDIR /app +# Install git +RUN apt-get update && \ + apt-get install -y --no-install-recommends git && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Use HTTPS instead of SSH for git clone RUN git clone https://github.com/twilio/twilio-java.git WORKDIR /app/twilio-java/ From 959f58c1b31871f2136adf8aa185da5e6341b337 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Thu, 6 Nov 2025 12:57:10 +0530 Subject: [PATCH 9/9] chore: use eclipse temurin 8 --- examples/java/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/java/Dockerfile b/examples/java/Dockerfile index c413e7997..313a202ee 100644 --- a/examples/java/Dockerfile +++ b/examples/java/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:11-jre +FROM eclipse-temurin:8-jdk # Install Maven with proper error handling RUN apt-get update && \