diff --git a/bin/configs/avro-schema-enums.yaml b/bin/configs/avro-schema-enums.yaml new file mode 100644 index 00000000000..32afa02e8c9 --- /dev/null +++ b/bin/configs/avro-schema-enums.yaml @@ -0,0 +1,4 @@ +generatorName: avro-schema +outputDir: samples/openapi3/schema/valid-enums/avro-schema-enum +inputSpec: modules/openapi-generator/src/test/resources/3_0/avro-schema/valid-enums.yaml +templateDir: modules/openapi-generator/src/main/resources/avro-schema diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroSchemaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroSchemaCodegen.java index 8918cd88fe0..69bcb447628 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroSchemaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroSchemaCodegen.java @@ -25,12 +25,20 @@ import org.openapitools.codegen.model.ModelsMap; import java.io.File; import java.util.Arrays; +import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static org.openapitools.codegen.utils.StringUtils.camelize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class AvroSchemaCodegen extends DefaultCodegen implements CodegenConfig { + private final Logger LOGGER = LoggerFactory.getLogger(AvroSchemaCodegen.class); private static final String AVRO = "avro-schema"; protected String packageName = "model"; @@ -148,4 +156,44 @@ public class AvroSchemaCodegen extends DefaultCodegen implements CodegenConfig { return input; } + @Override + protected List> buildEnumVars(List values, String dataType) { + List sanitizedValues = values.stream().map(Object::toString).map(this::sanitizeEnumValue) + .collect(Collectors.toList()); + removeEnumValueCollisions(sanitizedValues); + return super.buildEnumVars(sanitizedValues, dataType); + } + + /** + * Valid enums in Avro need to adhere to [A-Za-z_][A-Za-z0-9_]* + * See https://avro.apache.org/docs/1.12.0/specification/#enums + */ + private String sanitizeEnumValue(String value) { + // Replace any non-alphanumeric characters with an underscore + String sanitizedValue = value.replaceAll("[^A-Za-z0-9_]", "_"); + // If the enum starts with a number, prefix it with an underscore + sanitizedValue = sanitizedValue.replaceAll("^([0-9])", "_$1"); + return sanitizedValue; + } + + private void removeEnumValueCollisions(List values) { + Collections.reverse(values); + for (int i = 0; i < values.size(); i++) { + final String value = values.get(i).toString(); + long count = values.stream().filter(v1 -> v1.equals(value)).count(); + if (count > 1) { + String uniqueEnumValue = getUniqueEnumValue(value.toString(), values); + LOGGER.debug("Changing duplicate enumeration value from " + value + " to " + uniqueEnumValue); + values.set(i, uniqueEnumValue); + } + } + Collections.reverse(values); + } + + private String getUniqueEnumValue(String value, List values) { + long count = values.stream().filter(v -> v.equals(value)).count(); + return count > 1 + ? getUniqueEnumValue(value + count, values) + : value; + } } \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/avro-schema/valid-enums.yaml b/modules/openapi-generator/src/test/resources/3_0/avro-schema/valid-enums.yaml new file mode 100644 index 00000000000..d1ebb181647 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/avro-schema/valid-enums.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Test for valid enums +paths: + /test: + get: + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Sample' +components: + schemas: + Sample: + properties: + type: + enum: + - 'a' + - 'b' + # This enum is invalid for Avro schemas, as it contains a `-` + - 'uh-oh' + # This next one starts with a number, which is invalid for Avro schemas + - '0h_oh' + # The next two is to make sure collisions are resolved properly + - 'coll-ision' + - 'coll_ision' + type: 'string' \ No newline at end of file diff --git a/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator-ignore b/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator/FILES b/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator/FILES new file mode 100644 index 00000000000..d9ea5ba5025 --- /dev/null +++ b/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator/FILES @@ -0,0 +1 @@ +Sample.avsc diff --git a/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator/VERSION b/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator/VERSION new file mode 100644 index 00000000000..17f2442ff3b --- /dev/null +++ b/samples/openapi3/schema/valid-enums/avro-schema-enum/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.9.0-SNAPSHOT diff --git a/samples/openapi3/schema/valid-enums/avro-schema-enum/Sample.avsc b/samples/openapi3/schema/valid-enums/avro-schema-enum/Sample.avsc new file mode 100644 index 00000000000..23281b4a7dd --- /dev/null +++ b/samples/openapi3/schema/valid-enums/avro-schema-enum/Sample.avsc @@ -0,0 +1,26 @@ +{ + "namespace": "model", + "type": "record", + "doc": "", + "name": "Sample", + "fields": [ + { + "name": "type", + "type": ["null", { + "type": "enum", + "name": "Sample_type", + "symbols": [ + "a", + "b", + "uh_oh", + "_0h_oh", + "coll_ision", + "coll_ision2" + ] + }], + "doc": "", + "default": null + } + ] + +}