diff --git a/bin/openapi3/avro-petstore.sh b/bin/openapi3/avro-petstore.sh new file mode 100644 index 00000000000..f1296f2c122 --- /dev/null +++ b/bin/openapi3/avro-petstore.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +SCRIPT="$0" +echo "# START SCRIPT: $SCRIPT" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g avro -o samples/openapi3/schema/petstore/avro $@" + +java $JAVA_OPTS -jar $executable $ags diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroCodegen.java new file mode 100644 index 00000000000..a4875549df7 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AvroCodegen.java @@ -0,0 +1,111 @@ +/* + * Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * Licensed 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 org.openapitools.codegen.languages; + +import org.openapitools.codegen.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; + +import static org.openapitools.codegen.utils.StringUtils.camelize; + +public class AvroCodegen extends DefaultCodegen implements CodegenConfig { + private static final String AVRO = "avro"; + + public AvroCodegen() { + outputFolder = "generated-code/avro"; + modelTemplateFiles.put("model.mustache", ".avsc"); + apiPackage = "api"; + modelPackage = "model"; + + + // default HIDE_GENERATION_TIMESTAMP to true + hideGenerationTimestamp = Boolean.TRUE; + + languageSpecificPrimitives = new HashSet<>( + Arrays.asList("null", "boolean", "int", "integer", "long", "float", "double", "bytes", "string", + "BigDecimal", "UUID", "number", "date", "DateTime") + ); + defaultIncludes = new HashSet<>(languageSpecificPrimitives); + + instantiationTypes.put("array", "Array"); + instantiationTypes.put("list", "Array"); + instantiationTypes.put("map", "Object"); + typeMapping.clear(); + typeMapping.put("number", "double"); + typeMapping.put("DateTime", "string"); + typeMapping.put("date", "string"); + typeMapping.put("short", "int"); + typeMapping.put("char", "string"); + typeMapping.put("integer", "int"); + typeMapping.put("ByteArray", "bytes"); + typeMapping.put("binary", "File"); + typeMapping.put("file", "File"); + typeMapping.put("UUID", "string"); + typeMapping.put("BigDecimal", "string"); + + importMapping.clear(); + + cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC).defaultValue("src")); + cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC)); + cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC)); + cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC)); + cliOptions.add(new CliOption(CodegenConstants.LICENSE_NAME, "name of the license the project uses (Default: using info.license.name)")); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); + + embeddedTemplateDir = AVRO; + templateDir = AVRO; + } + + @Override + public CodegenType getTag() { + return CodegenType.SCHEMA; + } + + @Override + public String getName() { + return "avro"; + } + + @Override + public String getHelp() { + return "Generates a Avro model."; + } + + @Override + public String modelFileFolder() { + return outputFolder + "/" ; + } + + @Override + public Map postProcessModels(Map objs) { + return postProcessModelsEnum(objs); + } + + @Override + protected void setNonArrayMapProperty(CodegenProperty property, String type) { + super.setNonArrayMapProperty(property, type); + if (property.isModel) { + property.dataType = camelize(modelNamePrefix + property.dataType + modelNameSuffix ); + } + } + +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 9a8fba9fc43..865f3b24c89 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -4,6 +4,7 @@ org.openapitools.codegen.languages.AndroidClientCodegen org.openapitools.codegen.languages.Apache2ConfigCodegen org.openapitools.codegen.languages.ApexClientCodegen org.openapitools.codegen.languages.AspNetCoreServerCodegen +org.openapitools.codegen.languages.AvroCodegen org.openapitools.codegen.languages.BashClientCodegen org.openapitools.codegen.languages.CLibcurlClientCodegen org.openapitools.codegen.languages.ClojureClientCodegen diff --git a/modules/openapi-generator/src/main/resources/avro/model.mustache b/modules/openapi-generator/src/main/resources/avro/model.mustache new file mode 100644 index 00000000000..59e7558333f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/avro/model.mustache @@ -0,0 +1,8 @@ +{{#models}}{{#model}}{ + "namespace": "{{package}}", + "type": "{{#isEnum}}enum{{/isEnum}}{{^isEnum}}record{{/isEnum}}", + "doc": "{{{description}}}", + "name": "{{{classname}}}", +{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>pojo}}{{/isEnum}} +} +{{/model}}{{/models}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/avro/modelEnum.mustache b/modules/openapi-generator/src/main/resources/avro/modelEnum.mustache new file mode 100644 index 00000000000..b0659602bd4 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/avro/modelEnum.mustache @@ -0,0 +1,3 @@ + "symbols": [{{#allowableValues}}{{#enumVars}} + {{{value}}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} + ] \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/avro/pojo.mustache b/modules/openapi-generator/src/main/resources/avro/pojo.mustache new file mode 100644 index 00000000000..83795fb88d5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/avro/pojo.mustache @@ -0,0 +1,7 @@ + "fields": [{{#vars}}{{^-first}},{{/-first}} + { + "name": "{{baseName}}", + "type": {{^required}}["null", {{/required}}{{>typeProperty}}{{^required}}]{{/required}}, + "doc": "{{{description}}}" + }{{/vars}} + ] \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/avro/typeArray.mustache b/modules/openapi-generator/src/main/resources/avro/typeArray.mustache new file mode 100644 index 00000000000..01aba0e2043 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/avro/typeArray.mustache @@ -0,0 +1,4 @@ +{ + "type": "{{dataType}}", + {{#items}}"items": "{{#isModel}}{{package}}.{{/isModel}}{{dataType}}"{{/items}} + } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/avro/typeEnum.mustache b/modules/openapi-generator/src/main/resources/avro/typeEnum.mustache new file mode 100644 index 00000000000..9925382e34e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/avro/typeEnum.mustache @@ -0,0 +1,7 @@ +{ + "type": "enum", + "name": "{{classname}}_{{name}}", + "symbols": [{{#allowableValues}}{{#enumVars}} + {{{value}}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} + ] + } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/avro/typeProperty.mustache b/modules/openapi-generator/src/main/resources/avro/typeProperty.mustache new file mode 100644 index 00000000000..ffad928c07a --- /dev/null +++ b/modules/openapi-generator/src/main/resources/avro/typeProperty.mustache @@ -0,0 +1 @@ +{{^isEnum}}{{^isContainer}}{{#isPrimitiveType}}"{{dataType}}"{{/isPrimitiveType}}{{#isModel}}"{{package}}.{{dataType}}"{{/isModel}}{{/isContainer}}{{#isContainer}}{{>typeArray}}{{/isContainer}}{{/isEnum}}{{#isEnum}}{{>typeEnum}}{{/isEnum}} \ No newline at end of file diff --git a/samples/openapi3/schema/petstore/avro/.openapi-generator-ignore b/samples/openapi3/schema/petstore/avro/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/.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/petstore/avro/.openapi-generator/VERSION b/samples/openapi3/schema/petstore/avro/.openapi-generator/VERSION new file mode 100644 index 00000000000..2f81801b794 --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/.openapi-generator/VERSION @@ -0,0 +1 @@ +4.1.1-SNAPSHOT \ No newline at end of file diff --git a/samples/openapi3/schema/petstore/avro/ApiResponse.avsc b/samples/openapi3/schema/petstore/avro/ApiResponse.avsc new file mode 100644 index 00000000000..d3ce5cc6aea --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/ApiResponse.avsc @@ -0,0 +1,23 @@ +{ + "namespace": "model", + "type": "record", + "doc": "Describes the result of uploading an image resource", + "name": "ApiResponse", + "fields": [ + { + "name": "code", + "type": ["null", "int"], + "doc": "" + }, + { + "name": "type", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "message", + "type": ["null", "string"], + "doc": "" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/Category.avsc b/samples/openapi3/schema/petstore/avro/Category.avsc new file mode 100644 index 00000000000..527f2d389cd --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/Category.avsc @@ -0,0 +1,18 @@ +{ + "namespace": "model", + "type": "record", + "doc": "A category for a pet", + "name": "Category", + "fields": [ + { + "name": "id", + "type": ["null", "long"], + "doc": "" + }, + { + "name": "name", + "type": ["null", "string"], + "doc": "" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/InlineObject.avsc b/samples/openapi3/schema/petstore/avro/InlineObject.avsc new file mode 100644 index 00000000000..70af82014c9 --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/InlineObject.avsc @@ -0,0 +1,18 @@ +{ + "namespace": "model", + "type": "record", + "doc": "", + "name": "InlineObject", + "fields": [ + { + "name": "name", + "type": ["null", "string"], + "doc": "Updated name of the pet" + }, + { + "name": "status", + "type": ["null", "string"], + "doc": "Updated status of the pet" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/InlineObject1.avsc b/samples/openapi3/schema/petstore/avro/InlineObject1.avsc new file mode 100644 index 00000000000..322dae3751e --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/InlineObject1.avsc @@ -0,0 +1,18 @@ +{ + "namespace": "model", + "type": "record", + "doc": "", + "name": "InlineObject1", + "fields": [ + { + "name": "additionalMetadata", + "type": ["null", "string"], + "doc": "Additional data to pass to server" + }, + { + "name": "file", + "type": ["null", "model.File"], + "doc": "file to upload" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/Order.avsc b/samples/openapi3/schema/petstore/avro/Order.avsc new file mode 100644 index 00000000000..945f42d579e --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/Order.avsc @@ -0,0 +1,46 @@ +{ + "namespace": "model", + "type": "record", + "doc": "An order for a pets from the pet store", + "name": "Order", + "fields": [ + { + "name": "id", + "type": ["null", "long"], + "doc": "" + }, + { + "name": "petId", + "type": ["null", "long"], + "doc": "" + }, + { + "name": "quantity", + "type": ["null", "int"], + "doc": "" + }, + { + "name": "shipDate", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "status", + "type": ["null", { + "type": "enum", + "name": "Order_status", + "symbols": [ + "placed", + "approved", + "delivered" + ] + }], + "doc": "Order Status" + }, + { + "name": "complete", + "type": ["null", "boolean"], + "doc": "" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/Pet.avsc b/samples/openapi3/schema/petstore/avro/Pet.avsc new file mode 100644 index 00000000000..46ccf5f3d66 --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/Pet.avsc @@ -0,0 +1,52 @@ +{ + "namespace": "model", + "type": "record", + "doc": "A pet for sale in the pet store", + "name": "Pet", + "fields": [ + { + "name": "id", + "type": ["null", "long"], + "doc": "" + }, + { + "name": "category", + "type": ["null", "model.Category"], + "doc": "" + }, + { + "name": "name", + "type": "string", + "doc": "" + }, + { + "name": "photoUrls", + "type": { + "type": "array", + "items": "string" + }, + "doc": "" + }, + { + "name": "tags", + "type": ["null", { + "type": "array", + "items": "model.Tag" + }], + "doc": "" + }, + { + "name": "status", + "type": ["null", { + "type": "enum", + "name": "Pet_status", + "symbols": [ + "available", + "pending", + "sold" + ] + }], + "doc": "pet status in the store" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/Tag.avsc b/samples/openapi3/schema/petstore/avro/Tag.avsc new file mode 100644 index 00000000000..ec31d8fb17a --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/Tag.avsc @@ -0,0 +1,18 @@ +{ + "namespace": "model", + "type": "record", + "doc": "A tag for a pet", + "name": "Tag", + "fields": [ + { + "name": "id", + "type": ["null", "long"], + "doc": "" + }, + { + "name": "name", + "type": ["null", "string"], + "doc": "" + } + ] +} diff --git a/samples/openapi3/schema/petstore/avro/User.avsc b/samples/openapi3/schema/petstore/avro/User.avsc new file mode 100644 index 00000000000..2654a817946 --- /dev/null +++ b/samples/openapi3/schema/petstore/avro/User.avsc @@ -0,0 +1,48 @@ +{ + "namespace": "model", + "type": "record", + "doc": "A User who is purchasing from the pet store", + "name": "User", + "fields": [ + { + "name": "id", + "type": ["null", "long"], + "doc": "" + }, + { + "name": "username", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "firstName", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "lastName", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "email", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "password", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "phone", + "type": ["null", "string"], + "doc": "" + }, + { + "name": "userStatus", + "type": ["null", "int"], + "doc": "User Status" + } + ] +}