diff --git a/.github/workflows/update-specs-and-client-libraries.yaml b/.github/workflows/update-specs-and-client-libraries.yaml index d31f0132..a7f05a2e 100644 --- a/.github/workflows/update-specs-and-client-libraries.yaml +++ b/.github/workflows/update-specs-and-client-libraries.yaml @@ -58,7 +58,7 @@ jobs: php_version: ${{ steps.generator.outputs.php_version }} python_version: ${{ steps.generator.outputs.python_version }} container: - image: openapitools/openapi-generator-cli:v7.4.0 + image: openapitools/openapi-generator-cli:v7.5.0 env: OPENAPI_GENERATOR_COMMAND: docker-entrypoint.sh BUMP_CLIENT_LIBRARY_VERSION: ${{ inputs.type-of-change }} diff --git a/generators/java/okhttp-gson/templates/SHA256SUM b/generators/java/okhttp-gson/templates/SHA256SUM index d976cf95..0a11f4eb 100644 --- a/generators/java/okhttp-gson/templates/SHA256SUM +++ b/generators/java/okhttp-gson/templates/SHA256SUM @@ -1,4 +1,4 @@ 16502193337397367078434a27f67edfc6410f4c06d12db876155885d6a49394 ./README.mustache -c3d88c055ea33b1ba005b4344a2a95d7bf1d3ba4d4f931e26575c87a1e1c3c4a ./libraries/okhttp-gson/ApiClient.mustache -f5f282511d50815920f98c963b5c46ecbe5ca7d4103c209ef856bf02925f0934 ./libraries/okhttp-gson/oneof_model.mustache +7b635a5f3fcc4cb2ace38f0dd0ca8252a78090e592a6c35fe5a08f7bc407ef6b ./libraries/okhttp-gson/ApiClient.mustache +0e06162937a3175d59b3bdb9fa249de9888ea0d0a06cfbae543f53720ff706e5 ./libraries/okhttp-gson/oneof_model.mustache diff --git a/generators/java/okhttp-gson/templates/libraries/okhttp-gson/oneof_model.mustache b/generators/java/okhttp-gson/templates/libraries/okhttp-gson/oneof_model.mustache index 3fb5b7ce..288fe4a5 100644 --- a/generators/java/okhttp-gson/templates/libraries/okhttp-gson/oneof_model.mustache +++ b/generators/java/okhttp-gson/templates/libraries/okhttp-gson/oneof_model.mustache @@ -54,8 +54,8 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im {{/isArray}} {{#isArray}} - final Type typeInstance = new TypeToken>(){}.getType(); - final TypeAdapter<{{{dataType}}}> adapter{{complexType}}List = (TypeAdapter>) gson.getDelegateAdapter(this, TypeToken.get(typeInstance)); + final Type typeInstance = new TypeToken<{{{dataType}}}>(){}.getType(); + final TypeAdapter<{{{dataType}}}> adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} = (TypeAdapter<{{{dataType}}}>) gson.getDelegateAdapter(this, TypeToken.get(typeInstance)); {{/isArray}} {{/oneOf}} {{/composedSchemas}} @@ -77,23 +77,25 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im // check if the actual instance is of the type `{{{dataType}}}` if (value.getActualInstance() instanceof {{#isArray}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) { {{#isPrimitiveType}} - JsonPrimitive primitive = adapter{{{dataType}}}.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonPrimitive(); - elementAdapter.write(out, primitive); - return; + JsonPrimitive primitive = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonPrimitive(); + elementAdapter.write(out, primitive); + return; {{/isPrimitiveType}} + {{^isPrimitiveType}} {{#isArray}} - List list = (List) value.getActualInstance(); - if(list.get(0) instanceof {{complexType}}) { - JsonArray array = adapter{{{complexType}}}List.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonArray(); - elementAdapter.write(out, array); - return; - } + List list = (List) value.getActualInstance(); + if (list.get(0) instanceof {{{items.dataType}}}) { + JsonArray array = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonArray(); + elementAdapter.write(out, array); + return; + } {{/isArray}} + {{/isPrimitiveType}} {{^isArray}} {{^isPrimitiveType}} - JsonElement element = adapter{{{dataType}}}.toJsonTree(({{{dataType}}})value.getActualInstance()); - elementAdapter.write(out, element); - return; + JsonElement element = adapter{{{dataType}}}.toJsonTree(({{{dataType}}})value.getActualInstance()); + elementAdapter.write(out, element); + return; {{/isPrimitiveType}} {{/isArray}} } @@ -145,62 +147,65 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im {{^hasVars}} // deserialize {{{dataType}}} try { - // validate the JSON object to see if any exception is thrown + // validate the JSON object to see if any exception is thrown + {{^isArray}} {{#isNumber}} - if(!jsonElement.getAsJsonPrimitive().isNumber()) { - throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); - } - actualAdapter = adapter{{{dataType}}}; + if (!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}; {{/isNumber}} {{^isNumber}} {{#isPrimitiveType}} - if(!jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { - throw new IllegalArgumentException(String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); - } - actualAdapter = adapter{{{dataType}}}; + if (!jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}; {{/isPrimitiveType}} + {{/isNumber}} + {{^isNumber}} {{^isPrimitiveType}} - {{^isArray}} - {{{dataType}}}.validateJsonElement(jsonElement); - actualAdapter = adapter{{{dataType}}}; - {{/isArray}} + {{{dataType}}}.validateJsonElement(jsonElement); + actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}; {{/isPrimitiveType}} {{/isNumber}} + {{/isArray}} {{#isArray}} - if (!jsonElement.isJsonArray()) { - throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString())); - } - - JsonArray array = jsonElement.getAsJsonArray(); - // validate array items - for(JsonElement element : array) { - {{#items}} - {{#isNumber}} - if(!jsonElement.getAsJsonPrimitive().isNumber()) { - throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + if (!jsonElement.isJsonArray()) { + throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString())); } - actualAdapter = adapter{{{dataType}}}; - {{/isNumber}} - {{^isNumber}} - {{#isPrimitiveType}} - if(!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { - throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); - } - {{/isPrimitiveType}} - {{^isPrimitiveType}} - {{{dataType}}}.validateJsonElement(element); - {{/isPrimitiveType}} - {{/isNumber}} - {{/items}} - } - actualAdapter = adapter{{{complexType}}}List; + + JsonArray array = jsonElement.getAsJsonArray(); + // validate array items + for(JsonElement element : array) { + {{#items}} + {{#isNumber}} + if (!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isNumber}} + {{^isNumber}} + {{#isPrimitiveType}} + if (!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isPrimitiveType}} + {{/isNumber}} + {{^isNumber}} + {{^isPrimitiveType}} + {{{dataType}}}.validateJsonElement(element); + {{/isPrimitiveType}} + {{/isNumber}} + {{/items}} + } + actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}; {{/isArray}} - match++; - log.log(Level.FINER, "Input data matches schema '{{{dataType}}}'"); + match++; + log.log(Level.FINER, "Input data matches schema '{{{dataType}}}'"); } catch (Exception e) { - // deserialization failed, continue - errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage())); - log.log(Level.FINER, "Input data does not match schema '{{{dataType}}}'", e); + // deserialization failed, continue + errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage())); + log.log(Level.FINER, "Input data does not match schema '{{{dataType}}}'", e); } {{/hasVars}} {{#hasVars}} @@ -287,10 +292,10 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im if (instance instanceof {{#isArray}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) { {{#isArray}} List list = (List) instance; - if(list.get(0) instanceof {{complexType}}) { - super.setActualInstance(instance); - return; - } + if (list.get(0) instanceof {{{items.dataType}}}) { + super.setActualInstance(instance); + return; + } {{/isArray}} {{^isArray}} super.setActualInstance(instance); @@ -310,6 +315,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im * * @return The actual instance ({{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}) */ + @SuppressWarnings("unchecked") @Override public Object getActualInstance() { return super.getActualInstance(); @@ -325,113 +331,117 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im * @return The actual instance of `{{{dataType}}}` * @throws ClassCastException if the instance is not `{{{dataType}}}` */ - public {{{dataType}}} get{{#isArray}}{{complexType}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}() throws ClassCastException { + public {{{dataType}}} get{{#isArray}}{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}() throws ClassCastException { return ({{{dataType}}})super.getActualInstance(); } {{/vendorExtensions.x-duplicated-data-type}} {{/oneOf}} {{/composedSchemas}} - /** - * Validates the JSON Element and throws an exception if issues found - * - * @param jsonElement JSON Element - * @throws IOException if the JSON Element is invalid with respect to {{classname}} - */ - public static void validateJsonElement(JsonElement jsonElement) throws IOException { - // validate oneOf schemas one by one - int validCount = 0; - ArrayList errorMessages = new ArrayList<>(); - {{#composedSchemas}} - {{#oneOf}} - {{^vendorExtensions.x-duplicated-data-type}} - // validate the json string with {{{dataType}}} - try { - {{^hasVars}} - {{#isNumber}} - if(!jsonElement.getAsJsonPrimitive().isNumber()) { - throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); - } - {{/isNumber}} - {{^isNumber}} - {{#isPrimitiveType}} - if(!jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { - throw new IllegalArgumentException(String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); - } - {{/isPrimitiveType}} - {{^isPrimitiveType}} - {{^isArray}} - {{{dataType}}}.validateJsonElement(jsonElement); - {{/isArray}} - {{/isPrimitiveType}} - {{/isNumber}} - {{#isArray}} - if (!jsonElement.isJsonArray()) { - throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString())); - } - JsonArray array = jsonElement.getAsJsonArray(); - // validate array items - for(JsonElement element : array) { - {{#items}} + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to {{classname}} + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + // validate oneOf schemas one by one + int validCount = 0; + ArrayList errorMessages = new ArrayList<>(); + {{#composedSchemas}} + {{#oneOf}} + {{^vendorExtensions.x-duplicated-data-type}} + // validate the json string with {{{dataType}}} + try { + {{^hasVars}} + {{^isArray}} {{#isNumber}} - if(!jsonElement.getAsJsonPrimitive().isNumber()) { - throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); - } + if (!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } {{/isNumber}} {{^isNumber}} {{#isPrimitiveType}} - if(!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { - throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); - } + if (!jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } {{/isPrimitiveType}} + {{/isNumber}} + {{^isNumber}} {{^isPrimitiveType}} - {{{dataType}}}.validateJsonElement(element); + {{{dataType}}}.validateJsonElement(jsonElement); {{/isPrimitiveType}} {{/isNumber}} - {{/items}} - } - {{/isArray}} - {{/hasVars}} - {{#hasVars}} - {{{.}}}.validateJsonElement(jsonElement); - validCount++; - {{/hasVars}} - validCount++; - } catch (Exception e) { - errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage())); - // continue to the next one - } - {{/vendorExtensions.x-duplicated-data-type}} - {{/oneOf}} - {{/composedSchemas}} - {{! Updated check, we might have more than one matching report, anyway we've discriminator - BEGIN }} - if (validCount < 1) { - throw new IOException(String.format("The JSON string is invalid for {{classname}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. %d class(es) match the result, expected at least 1. Detailed failure message for oneOf schemas: %s. JSON: %s", validCount, errorMessages, jsonElement.toString())); + {{/isArray}} + {{#isArray}} + if (!jsonElement.isJsonArray()) { + throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString())); + } + JsonArray array = jsonElement.getAsJsonArray(); + // validate array items + for(JsonElement element : array) { + {{#items}} + {{#isNumber}} + if (!jsonElement.getAsJsonPrimitive().isNumber()) { + throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isNumber}} + {{^isNumber}} + {{#isPrimitiveType}} + if (!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { + throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString())); + } + {{/isPrimitiveType}} + {{/isNumber}} + {{^isNumber}} + {{^isPrimitiveType}} + {{{dataType}}}.validateJsonElement(element); + {{/isPrimitiveType}} + {{/isNumber}} + {{/items}} + } + {{/isArray}} + {{/hasVars}} + {{#hasVars}} + {{{.}}}.validateJsonElement(jsonElement); + validCount++; + {{/hasVars}} + validCount++; + } catch (Exception e) { + errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage())); + // continue to the next one + } + {{/vendorExtensions.x-duplicated-data-type}} + {{/oneOf}} + {{/composedSchemas}} + {{! Updated check, we might have more than one matching report, anyway we've discriminator - BEGIN }} + if (validCount < 1) { + throw new IOException(String.format("The JSON string is invalid for {{classname}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. %d class(es) match the result, expected 1. Detailed failure message for oneOf schemas: %s. JSON: %s", validCount, errorMessages, jsonElement.toString())); + } + {{! Updated check, we might have more than one matching report, anyway we've discriminator - END }} } - {{! Updated check, we might have more than one matching report, anyway we've discriminator - END }} - } - /** - * Create an instance of {{classname}} given an JSON string - * - * @param jsonString JSON string - * @return An instance of {{classname}} - * @throws IOException if the JSON string is invalid with respect to {{classname}} - */ - public static {{{classname}}} fromJson(String jsonString) throws IOException { - return JSON.getGson().fromJson(jsonString, {{{classname}}}.class); - } + /** + * Create an instance of {{classname}} given an JSON string + * + * @param jsonString JSON string + * @return An instance of {{classname}} + * @throws IOException if the JSON string is invalid with respect to {{classname}} + */ + public static {{{classname}}} fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, {{{classname}}}.class); + } - /** - * Convert an instance of {{classname}} to an JSON string - * - * @return JSON string - */ - public String toJson() { - return JSON.getGson().toJson(this); - } + /** + * Convert an instance of {{classname}} to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } - {{! Added block of code based on com/onfido/model/ReportShared.java - BEGIN }} + {{! Added block of code based on com/onfido/model/ReportShared.java - BEGIN }} /** * Give access to shared properties. Read-only. diff --git a/generators/python/urllib3/templates/SHA256SUM b/generators/python/urllib3/templates/SHA256SUM index 8aa3cfd3..9ad81978 100644 --- a/generators/python/urllib3/templates/SHA256SUM +++ b/generators/python/urllib3/templates/SHA256SUM @@ -2,4 +2,4 @@ 47fdf5141b3d999914c33faff1626c6ac2f00f87fcf9653814084f1dc67351d9 ./README.mustache 6a196e67020d765512f0c8c88afc39ef9d3cacdd50a9eba6731a6dbb1997c6e5 ./__init__package.mustache e589dfcb5f8243b7e87998c012262d20db37c8dd985759232aad5e846bccd2bb ./configuration.mustache -8460a5d2eef3bdc62748ed011517629dd4d0578ef81a6b378f96d79b8a78f17b ./rest.mustache +36cae3e3b78cb80e1bdcc3c3f30ff58dc03d04561ed1559a92bfb07b934a8cf2 ./rest.mustache diff --git a/generators/python/urllib3/templates/rest.mustache b/generators/python/urllib3/templates/rest.mustache index 5fd4f10b..5ea2d1c1 100644 --- a/generators/python/urllib3/templates/rest.mustache +++ b/generators/python/urllib3/templates/rest.mustache @@ -195,6 +195,8 @@ class RESTClientObject: # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, diff --git a/shell/generate.sh b/shell/generate.sh index cf0d2437..1cf983c1 100755 --- a/shell/generate.sh +++ b/shell/generate.sh @@ -10,7 +10,7 @@ COMMON_CONFIG_FILE="generators/common/config.yaml" GENERATORS=${*:-`find generators -name 'config.yaml' -exec dirname {} \; | sed 's/generators\///'`} GENERATED_CONFIG_FILES="" -OPENAPI_GENERATOR_VERSION=${OPENAPI_GENERATOR_VERSION:-v7.4.0} +OPENAPI_GENERATOR_VERSION=${OPENAPI_GENERATOR_VERSION:-v7.5.0} OPENAPI_GENERATOR_COMMAND=${OPENAPI_GENERATOR_COMMAND:-\ docker run --rm -v "$(pwd):/local" -w /local \ openapitools/openapi-generator-cli:${OPENAPI_GENERATOR_VERSION}}