diff --git a/bin/kotlin-vertx-server-petstore.sh b/bin/kotlin-vertx-server-petstore.sh
new file mode 100755
index 000000000000..73d0d087f3bd
--- /dev/null
+++ b/bin/kotlin-vertx-server-petstore.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+SCRIPT="$0"
+
+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/2_0/petstore.yaml -g kotlin-vertx -o samples/server/petstore/kotlin/vertx"
+
+java ${JAVA_OPTS} -jar ${executable} ${ags}
diff --git a/bin/windows/kotlin-vertx-server-petstore.bat b/bin/windows/kotlin-vertx-server-petstore.bat
new file mode 100644
index 000000000000..6fd12f43d82c
--- /dev/null
+++ b/bin/windows/kotlin-vertx-server-petstore.bat
@@ -0,0 +1,10 @@
+set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
+
+If Not Exist %executable% (
+ mvn clean package
+)
+
+REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties
+set ags=generate --artifact-id "kotlin-vertx-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g kotlin-vertx -o samples\server\petstore\kotlin\vertx
+
+java %JAVA_OPTS% -jar %executable% %ags%
diff --git a/docs/generators.md b/docs/generators.md
index 2bb9b1f5e28e..808b3cc5cb42 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -95,6 +95,7 @@ The following generators are available:
* [jaxrs-spec](generators/jaxrs-spec)
* [kotlin-server](generators/kotlin-server)
* [kotlin-spring](generators/kotlin-spring)
+* [korlin-vertx](generators/kotlin-vertx)
* [nodejs-express-server (beta)](generators/nodejs-express-server)
* [nodejs-server-deprecated (deprecated)](generators/nodejs-server-deprecated)
* [php-laravel](generators/php-laravel)
diff --git a/docs/generators/kotlin-vertx.md b/docs/generators/kotlin-vertx.md
new file mode 100644
index 000000000000..6759792afbf8
--- /dev/null
+++ b/docs/generators/kotlin-vertx.md
@@ -0,0 +1,18 @@
+
+---
+id: generator-opts-server-kotlin-vertx
+title: Config Options for kotlin-vertx
+sidebar_label: kotlin-vertx
+---
+
+| Option | Description | Values | Default |
+| ------ | ----------- | ------ | ------- |
+|sourceFolder|source folder for generated code| |src/main/kotlin|
+|modelPackage|package for generated models| |org.openapitools.server.api.model|
+|apiPackage|package for generated api classes| |org.openapitools.server.api.verticle|
+|apiSuffix|suffix for api classes| |Api|
+|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
+|artifactId|Generated artifact id (name of jar).| |kotlin-server|
+|artifactVersion|Generated artifact's package version.| |1.0.0|
+|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
+|parcelizeModels|toggle "@Parcelize" for generated models| |null|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinVertxServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinVertxServerCodegen.java
new file mode 100644
index 000000000000..19863e9a67b8
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinVertxServerCodegen.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 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.CodegenConstants;
+import org.openapitools.codegen.CodegenType;
+import org.openapitools.codegen.SupportingFile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.Locale;
+
+public class KotlinVertxServerCodegen extends AbstractKotlinCodegen {
+
+ protected String rootPackage = "org.openapitools.server.api";
+ protected String apiVersion = "1.0.0-SNAPSHOT";
+
+ public static final String ROOT_PACKAGE = "rootPackage";
+
+ public static final String PROJECT_NAME = "projectName";
+
+ static Logger LOGGER = LoggerFactory.getLogger(KotlinVertxServerCodegen.class);
+
+ public CodegenType getTag() {
+ return CodegenType.SERVER;
+ }
+
+ public String getName() {
+ return "kotlin-vertx";
+ }
+
+ public String getHelp() {
+ return "Generates a kotlin-vertx server.";
+ }
+
+ public KotlinVertxServerCodegen() {
+ super();
+
+ outputFolder = "generated-code" + File.separator + "kotlin-vertx";
+ modelTemplateFiles.put("model.mustache", ".kt");
+
+ apiTestTemplateFiles.clear();
+ modelDocTemplateFiles.clear();
+ supportingFiles.clear();
+
+ apiTemplateFiles.clear();
+ apiTemplateFiles.put("api.mustache", ".kt");
+ apiTemplateFiles.put("apiProxy.mustache", "VertxProxyHandler.kt");
+ apiTemplateFiles.put("api_verticle.mustache","Verticle.kt");
+
+ embeddedTemplateDir = templateDir = "kotlin-vertx-server";
+ apiPackage = rootPackage + ".verticle";
+ modelPackage = rootPackage + ".model";
+ artifactId = "openapi-kotlin-vertx-server";
+ artifactVersion = apiVersion;
+
+ updateOption(CodegenConstants.API_PACKAGE, apiPackage);
+ updateOption(CodegenConstants.MODEL_PACKAGE, modelPackage);
+ additionalProperties.put(ROOT_PACKAGE, rootPackage);
+
+ supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
+ supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
+
+ }
+
+ @Override
+ public String escapeReservedWord(String name) {
+ return name;
+ }
+}
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 dcd64831edc6..5a6cb16c1ac2 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
@@ -28,6 +28,7 @@ org.openapitools.codegen.languages.ErlangClientCodegen
org.openapitools.codegen.languages.ErlangProperCodegen
org.openapitools.codegen.languages.ErlangServerCodegen
org.openapitools.codegen.languages.FlashClientCodegen
+org.openapitools.codegen.languages.FsharpGiraffeServerCodegen
org.openapitools.codegen.languages.GoClientCodegen
org.openapitools.codegen.languages.GoClientExperimentalCodegen
org.openapitools.codegen.languages.GoServerCodegen
@@ -38,6 +39,7 @@ org.openapitools.codegen.languages.GroovyClientCodegen
org.openapitools.codegen.languages.KotlinClientCodegen
org.openapitools.codegen.languages.KotlinServerCodegen
org.openapitools.codegen.languages.KotlinSpringServerCodegen
+org.openapitools.codegen.languages.KotlinVertxServerCodegen
org.openapitools.codegen.languages.HaskellHttpClientCodegen
org.openapitools.codegen.languages.HaskellServantCodegen
org.openapitools.codegen.languages.JavaClientCodegen
@@ -114,5 +116,4 @@ org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen
org.openapitools.codegen.languages.TypeScriptNodeClientCodegen
org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen
org.openapitools.codegen.languages.FsharpGiraffeServerCodegen
-
org.openapitools.codegen.languages.AsciidocDocumentationCodegen
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/README.mustache
new file mode 100644
index 000000000000..f4db05742d00
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/README.mustache
@@ -0,0 +1,76 @@
+# {{packageName}} - Kotlin Server library for {{appName}}
+
+## Requires
+
+* Kotlin 1.3.10
+* Maven 3.3
+
+## Build
+
+```
+mvn clean package
+```
+
+This runs all tests and packages the library.
+
+## Features/Implementation Notes
+
+* Supports JSON inputs/outputs and Form inputs.
+* Supports collection formats for query parameters: csv, tsv, ssv, pipes.
+* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions.
+
+{{#generateApiDocs}}
+
+ ## Documentation for API Endpoints
+
+ All URIs are relative to *{{{basePath}}}*
+
+ Class | Method | HTTP request | Description
+ ------------ | ------------- | ------------- | -------------
+ {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}}
+ {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
+{{/generateApiDocs}}
+
+{{#generateModelDocs}}
+
+ ## Documentation for Models
+
+ {{#modelPackage}}
+ {{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
+ {{/model}}{{/models}}
+ {{/modelPackage}}
+ {{^modelPackage}}
+ No model defined in this package
+ {{/modelPackage}}
+{{/generateModelDocs}}
+
+{{! TODO: optional documentation for authorization? }}
+## Documentation for Authorization
+
+{{^authMethods}}
+ All endpoints do not require authorization.
+{{/authMethods}}
+{{#authMethods}}
+ {{#last}}
+ Authentication schemes defined for the API:
+ {{/last}}
+{{/authMethods}}
+{{#authMethods}}
+
+ ### {{name}}
+
+ {{#isApiKey}}- **Type**: API key
+ - **API key parameter name**: {{keyParamName}}
+ - **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
+ {{/isApiKey}}
+ {{#isBasic}}- **Type**: HTTP basic authentication
+ {{/isBasic}}
+ {{#isOAuth}}- **Type**: OAuth
+ - **Flow**: {{flow}}
+ - **Authorization URL**: {{authorizationUrl}}
+ - **Scopes**: {{^scopes}}N/A{{/scopes}}
+ {{#scopes}} - {{scope}}: {{description}}
+ {{/scopes}}
+ {{/isOAuth}}
+
+{{/authMethods}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api.mustache
new file mode 100644
index 000000000000..279271960743
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api.mustache
@@ -0,0 +1,53 @@
+package {{package}}
+
+{{#imports}}import {{import}}
+{{/imports}}
+import io.vertx.core.Vertx
+import io.vertx.core.json.JsonObject
+import io.vertx.core.json.JsonArray
+import com.github.wooyme.openapi.Response
+import io.vertx.ext.web.api.OperationRequest
+import io.vertx.kotlin.ext.web.api.contract.openapi3.OpenAPI3RouterFactory
+import io.vertx.serviceproxy.ServiceBinder
+import io.vertx.ext.web.handler.CookieHandler
+import io.vertx.ext.web.handler.SessionHandler
+import io.vertx.ext.web.sstore.LocalSessionStore
+import java.util.List
+import java.util.Map
+
+
+interface {{classname}} {
+ fun init(vertx:Vertx,config:JsonObject)
+{{#operations}}
+ {{#operation}}
+ /* {{operationId}}
+ * {{summary}} */
+ suspend fun {{operationId}}({{#allParams}}{{paramName}}:{{^isFile}}{{{dataType}}}{{/isFile}}{{#isFile}}kotlin.collections.List{{/isFile}}{{^isRequired}}?{{/isRequired}},{{/allParams}}context:OperationRequest):Response<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>
+ {{/operation}}
+{{/operations}}
+ companion object {
+ const val address = "{{classname}}-service"
+ suspend fun createRouterFactory(vertx: Vertx,path:String): io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory {
+ val routerFactory = OpenAPI3RouterFactory.createAwait(vertx,path)
+ routerFactory.addGlobalHandler(CookieHandler.create())
+ routerFactory.addGlobalHandler(SessionHandler.create(LocalSessionStore.create(vertx)))
+ routerFactory.setExtraOperationContextPayloadMapper{
+ JsonObject().put("files",JsonArray(it.fileUploads().map { it.uploadedFileName() }))
+ }
+ val opf = routerFactory::class.java.getDeclaredField("operations")
+ opf.isAccessible = true
+ val operations = opf.get(routerFactory) as Map
+ for (m in {{classname}}::class.java.methods) {
+ val methodName = m.name
+ val op = operations[methodName]
+ if (op != null) {
+ val method = op::class.java.getDeclaredMethod("mountRouteToService",String::class.java,String::class.java)
+ method.isAccessible = true
+ method.invoke(op,address,methodName)
+ }
+ }
+ routerFactory.mountServiceInterface({{classname}}::class.java, address)
+ return routerFactory
+ }
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/apiProxy.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/apiProxy.mustache
new file mode 100644
index 000000000000..8c6f81f1b43f
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/apiProxy.mustache
@@ -0,0 +1,179 @@
+package {{package}}
+
+import io.vertx.core.Vertx
+import io.vertx.core.eventbus.Message
+import io.vertx.core.json.JsonObject
+import io.vertx.ext.web.api.OperationRequest
+import io.vertx.ext.web.api.OperationResponse
+import io.vertx.ext.web.api.generator.ApiHandlerUtils
+import io.vertx.serviceproxy.ProxyHandler
+import io.vertx.serviceproxy.ServiceException
+import io.vertx.serviceproxy.ServiceExceptionMessageCodec
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import io.vertx.kotlin.coroutines.dispatcher
+import io.vertx.core.json.Json
+import io.vertx.core.json.JsonArray
+import com.google.gson.reflect.TypeToken
+import com.google.gson.Gson
+{{#imports}}import {{import}}
+{{/imports}}
+
+class {{classname}}VertxProxyHandler(private val vertx: Vertx, private val service: {{classname}}, topLevel: Boolean, private val timeoutSeconds: Long) : ProxyHandler() {
+ private val timerID: Long
+ private var lastAccessed: Long = 0
+ init {
+ try {
+ this.vertx.eventBus().registerDefaultCodec(ServiceException::class.java,
+ ServiceExceptionMessageCodec())
+ } catch (ex: IllegalStateException) {}
+
+ if (timeoutSeconds != (-1).toLong() && !topLevel) {
+ var period = timeoutSeconds * 1000 / 2
+ if (period > 10000) {
+ period = 10000
+ }
+ this.timerID = vertx.setPeriodic(period) { this.checkTimedOut(it) }
+ } else {
+ this.timerID = -1
+ }
+ accessed()
+ }
+ private fun checkTimedOut(id: Long) {
+ val now = System.nanoTime()
+ if (now - lastAccessed > timeoutSeconds * 1000000000) {
+ close()
+ }
+ }
+
+ override fun close() {
+ if (timerID != (-1).toLong()) {
+ vertx.cancelTimer(timerID)
+ }
+ super.close()
+ }
+
+ private fun accessed() {
+ this.lastAccessed = System.nanoTime()
+ }
+ override fun handle(msg: Message) {
+ try {
+ val json = msg.body()
+ val action = msg.headers().get("action") ?: throw IllegalStateException("action not specified")
+ accessed()
+ val contextSerialized = json.getJsonObject("context") ?: throw IllegalStateException("Received action $action without OperationRequest \"context\"")
+ val context = OperationRequest(contextSerialized)
+ when (action) {
+ {{#operations}}{{#operation}}
+ "{{#vendorExtensions}}{{operationId}}{{/vendorExtensions}}" -> {
+ {{#hasParams}}
+ val params = context.params
+ {{#allParams}}
+ {{#isListContainer}}
+ val {{paramName}}Param = ApiHandlerUtils.searchJsonArrayInJson(params,"{{#isBodyParam}}body{{/isBodyParam}}{{^isBodyParam}}{{baseName}}{{/isBodyParam}}")
+ {{#required}}
+ if({{paramName}}Param == null){
+ throw IllegalArgumentException("{{paramName}} is required")
+ }
+ val {{paramName}}:{{{dataType}}} = Gson().fromJson({{paramName}}Param.encode()
+ , object : TypeToken>(){}.type)
+ {{/required}}
+ {{^required}}
+ val {{paramName}}:{{{dataType}}}? = if({{paramName}}Param == null) {{#defaultValue}}{{defaultValue}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}
+ else Gson().fromJson({{paramName}}Param.encode(),
+ , object : TypeToken>(){}.type)
+ {{/required}}
+ {{/isListContainer}}
+ {{^isListContainer}}
+ {{#isFile}}
+ val {{paramName}}Param = context.extra.getJsonArray("files")
+ {{#required}}
+ if ({{paramName}}Param == null) {
+ throw IllegalArgumentException("{{paramName}} is required")
+ }
+ val {{paramName}} = {{paramName}}Param.map{ java.io.File(it as String) }
+ {{/required}}
+ {{^required}}
+ val {{paramName}} = {{paramName}}Param?.map{ java.io.File(it as String) }
+ {{/required}}
+ {{/isFile}}
+ {{#isPrimitiveType}}
+ {{#isString}}
+ val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isString}}
+ {{#isDate}}
+ val {{paramName}} = java.time.LocalDate.parse(ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}"))
+ {{/isDate}}
+ {{#isDateTime}}
+ val {{paramName}} = java.time.LocalDateTime.parse(ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}"))
+ {{/isDateTime}}
+ {{#isEmail}}
+ val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isEmail}}
+ {{#isUuid}}
+ val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isUuid}}
+ {{#isNumber}}
+ val {{paramName}} = ApiHandlerUtils.searchDoubleInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isNumber}}
+ {{#isLong}}
+ val {{paramName}} = ApiHandlerUtils.searchLongInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isLong}}
+ {{#isInteger}}
+ val {{paramName}} = ApiHandlerUtils.searchIntegerInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isInteger}}
+ {{#isFloat}}
+ val {{paramName}} = ApiHandlerUtils.searchDoubleInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")?.toFloat()
+ {{/isFloat}}
+ {{#isDouble}}
+ val {{paramName}} = ApiHandlerUtils.searchDoubleInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isDouble}}
+ {{#isBoolean}}
+ val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")?.toBoolean()
+ {{/isBoolean}}
+ {{#isFreeFormObject}}
+ val {{paramName}} = ApiHandlerUtils.searchJsonObjectInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{/isFreeFormObject}}
+ {{#required}}
+ if({{paramName}} == null){
+ throw IllegalArgumentException("{{paramName}} is required")
+ }
+ {{/required}}
+ {{/isPrimitiveType}}
+ {{^isPrimitiveType}}
+ val {{paramName}}Param = ApiHandlerUtils.searchJsonObjectInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")
+ {{#required}}
+ if ({{paramName}}Param == null) {
+ throw IllegalArgumentException("{{paramName}} is required")
+ }
+ val {{paramName}} = Gson().fromJson({{paramName}}Param.encode(), {{{dataType}}}::class.java)
+ {{/required}}
+ {{^required}}
+ val {{paramName}} = if({{paramName}}Param ==null) null else Gson().fromJson({{paramName}}Param.encode(), {{{dataType}}}::class.java)
+ {{/required}}
+ {{/isPrimitiveType}}
+ {{/isListContainer}}
+ {{/allParams}}
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.{{operationId}}({{#hasParams}}{{#allParams}}{{paramName}},{{/allParams}}{{/hasParams}}context)
+ {{#isListContainer}}
+ val payload = JsonArray(Json.encode(result.payload)).toBuffer()
+ {{/isListContainer}}
+ {{^isListContainer}}
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ {{/isListContainer}}
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ {{/hasParams}}
+ }
+ {{/operation}}{{/operations}}
+ }
+ }catch (t: Throwable) {
+ msg.reply(ServiceException(500, t.message))
+ throw t
+ }
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_doc.mustache
new file mode 100644
index 000000000000..5a41503df5b9
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_doc.mustache
@@ -0,0 +1,42 @@
+# {{classname}}{{#description}}
+{{description}}{{/description}}
+
+All URIs are relative to *{{basePath}}*
+
+Method | HTTP request | Description
+------------- | ------------- | -------------
+{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
+{{/operation}}{{/operations}}
+
+{{#operations}}
+{{#operation}}
+
+# **{{operationId}}**
+> {{#returnType}}{{returnType}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
+
+{{summary}}{{#notes}}
+
+{{notes}}{{/notes}}
+
+### Parameters
+{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
+{{#allParams}} **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}{{#generateModelDocs}}[**{{dataType}}**]({{baseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{dataType}}**{{/generateModelDocs}}{{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}}
+{{/allParams}}
+
+### Return type
+
+{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#generateModelDocs}}[**{{returnType}}**]({{returnBaseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{returnType}}**{{/generateModelDocs}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}}
+
+### Authorization
+
+{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}}
+
+### HTTP request headers
+
+ - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
+ - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}}
+
+{{/operation}}
+{{/operations}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_verticle.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_verticle.mustache
new file mode 100644
index 000000000000..c168d12e03a3
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_verticle.mustache
@@ -0,0 +1,19 @@
+package {{package}}
+import io.vertx.core.Vertx
+import io.vertx.core.AbstractVerticle
+import io.vertx.serviceproxy.ServiceBinder
+
+fun main(){
+ Vertx.vertx().deployVerticle({{classname}}Verticle())
+}
+
+class {{classname}}Verticle:AbstractVerticle() {
+
+ override fun start() {
+ val instance = (javaClass.classLoader.loadClass("{{package}}.{{classname}}Impl").newInstance() as {{classname}})
+ instance.init(vertx,config())
+ ServiceBinder(vertx)
+ .setAddress({{classname}}.address)
+ .register({{classname}}::class.java,instance)
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/class_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/class_doc.mustache
new file mode 100644
index 000000000000..b363fc5a61f2
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/class_doc.mustache
@@ -0,0 +1,15 @@
+# {{classname}}
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+{{#vars}}**{{name}}** | {{#isEnum}}[**inline**](#{{datatypeWithEnum}}){{/isEnum}}{{^isEnum}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{complexType}}.md){{/isPrimitiveType}}{{/isEnum}} | {{description}} | {{^required}} [optional]{{/required}}{{#readOnly}} [readonly]{{/readOnly}}
+{{/vars}}
+{{#vars}}{{#isEnum}}
+
+{{!NOTE: see java's resources "pojo_doc.mustache" once enums are fully implemented}}
+## Enum: {{baseName}}
+Name | Value
+---- | -----{{#allowableValues}}
+{{name}} | {{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}
+{{/isEnum}}{{/vars}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class.mustache
new file mode 100644
index 000000000000..d4c099d64ea7
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class.mustache
@@ -0,0 +1,42 @@
+
+{{#parcelizeModels}}
+import android.os.Parcelable
+import kotlinx.android.parcel.Parcelize
+{{/parcelizeModels}}
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * {{{description}}}
+{{#vars}}
+ * @param {{name}} {{{description}}}
+{{/vars}}
+ */
+{{#parcelizeModels}}
+@Parcelize
+{{/parcelizeModels}}
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class {{classname}} (
+{{#requiredVars}}
+{{>data_class_req_var}}{{^-last}},
+{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}},
+{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>data_class_opt_var}}{{^-last}},
+{{/-last}}{{/optionalVars}}
+){{#parcelizeModels}} : Parcelable{{/parcelizeModels}} {
+{{#hasEnums}}{{#vars}}{{#isEnum}}
+ /**
+ * {{{description}}}
+ * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
+ */
+ enum class {{nameInCamelCase}}(val value: {{dataType}}){
+ {{#allowableValues}}{{#enumVars}}
+ {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
+ {{/enumVars}}{{/allowableValues}}
+ }
+{{/isEnum}}{{/vars}}{{/hasEnums}}
+ {{#requiredVars}}
+ var {{{name}}} get() = _{{{name}}} ?: throw IllegalArgumentException("{{{name}}} is required")
+ set(value){ _{{{name}}} = value }
+ {{/requiredVars}}
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_opt_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_opt_var.mustache
new file mode 100644
index 000000000000..809b00758683
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_opt_var.mustache
@@ -0,0 +1,4 @@
+{{#description}}
+ /* {{{description}}} */
+{{/description}}
+ var {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_req_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_req_var.mustache
new file mode 100644
index 000000000000..66ec56120bea
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_req_var.mustache
@@ -0,0 +1,4 @@
+{{#description}}
+ /* {{{description}}} */
+{{/description}}
+ @SerializedName("{{{name}}}") private var _{{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}?
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enumClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enumClass.mustache
new file mode 100644
index 000000000000..0867107d9930
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enumClass.mustache
@@ -0,0 +1,17 @@
+
+ public enum {{{datatypeWithEnum}}} {
+ {{#allowableValues}}{{#enumVars}}{{{name}}}({{{value}}}){{^-last}},
+ {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}}
+
+ private String value;
+
+ {{{datatypeWithEnum}}}(String value) {
+ this.value = value;
+ }
+
+ @Override
+ @JsonValue
+ public String toString() {
+ return value;
+ }
+ }
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_class.mustache
new file mode 100644
index 000000000000..791398b97894
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_class.mustache
@@ -0,0 +1,9 @@
+/**
+* {{{description}}}
+* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
+*/
+enum class {{classname}}(val value: {{dataType}}){
+{{#allowableValues}}{{#enumVars}}
+ {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
+{{/enumVars}}{{/allowableValues}}
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_doc.mustache
new file mode 100644
index 000000000000..fcb3d7e61aa6
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_doc.mustache
@@ -0,0 +1,7 @@
+# {{classname}}
+
+## Enum
+
+{{#allowableValues}}{{#enumVars}}
+ * `{{name}}` (value: `{{{value}}}`)
+{{/enumVars}}{{/allowableValues}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/licenseInfo.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/licenseInfo.mustache
new file mode 100644
index 000000000000..3a547de74bb7
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/licenseInfo.mustache
@@ -0,0 +1,11 @@
+/**
+* {{{appName}}}
+* {{{appDescription}}}
+*
+* {{#version}}The version of the OpenAPI document: {{{version}}}{{/version}}
+* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}}
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/model.mustache
new file mode 100644
index 000000000000..74b63c00c6f5
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/model.mustache
@@ -0,0 +1,11 @@
+{{>licenseInfo}}
+package {{modelPackage}}
+
+{{#imports}}import {{import}}
+{{/imports}}
+
+{{#models}}
+ {{#model}}
+ {{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{>data_class}}{{/isEnum}}
+ {{/model}}
+{{/models}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/pom.mustache
new file mode 100644
index 000000000000..08a7b3496ab3
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/pom.mustache
@@ -0,0 +1,190 @@
+
+ 4.0.0
+
+ {{groupId}}
+ {{artifactId}}
+ {{artifactVersion}}
+ jar
+
+ {{appName}}
+
+
+ UTF-8
+ 1.8
+ 1.3.10
+ true
+ 4.12
+ 3.4.1
+ 3.3
+ 1.0.2
+ 2.3
+ 2.7.4
+ 3.6.0
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+ io.vertx
+ vertx-unit
+ ${vertx.version}
+ test
+
+
+
+ com.github.wooyme
+ vertx-openapi-router
+ ${vertx-openapi-router.version}
+
+
+
+ com.google.code.gson
+ gson
+ 2.8.5
+
+
+
+ javax.annotation
+ javax.annotation-api
+ 1.2
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-core
+ RELEASE
+
+
+
+ io.vertx
+ vertx-core
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-web
+ ${vertx.version}
+
+
+
+ io.vertx
+ vertx-lang-kotlin
+ ${vertx.version}
+
+
+
+ io.vertx
+ vertx-lang-kotlin-coroutines
+ ${vertx.version}
+
+
+
+ io.swagger.parser.v3
+ swagger-parser
+ 2.0.5
+
+
+
+ io.vertx
+ vertx-web-api-contract
+ ${vertx.version}
+
+
+
+ io.vertx
+ vertx-service-proxy
+ ${vertx.version}
+
+
+
+ io.vertx
+ vertx-web-api-service
+ ${vertx.version}
+
+
+
+
+
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${kotlin.version}
+
+
+ compile
+
+ compile
+
+
+
+ ${project.basedir}/src/main/kotlin
+ ${project.basedir}/src/main/java
+
+ 1.8
+
+
+
+ test-compile
+
+ test-compile
+
+
+
+ ${project.basedir}/src/test/kotlin
+ ${project.basedir}/src/test/java
+
+ 1.8
+
+
+
+
+
+
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+ ${java.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+
+ package
+
+ shade
+
+
+
+
+
+ {{apiPackage}}.DefaultApiVerticleKt
+
+
+
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
+
+
+
+
+
+
+
\ No newline at end of file