diff --git a/README.md b/README.md
index 5b7cb2222bf..1ab9b53db13 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
| | Languages/Frameworks |
|-|-|
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.0, .NET Core 2.0), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Nim**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 8.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs)
-**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot, Ktor), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra)
+**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot, Ktor, Vertx), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra)
**API documentation generators** | **HTML**, **Confluence Wiki**, **Asciidoc**
**Configuration files** | [**Apache2**](https://httpd.apache.org/)
**Others** | **GraphQL**, **JMeter**, **MySQL Schema**, **Protocol Buffer**
@@ -748,6 +748,7 @@ Here is a list of template creators:
* JAX-RS RestEasy (JBoss EAP): @jfiala
* Kotlin: @jimschubert [:heart:](https://www.patreon.com/jimschubert)
* Kotlin (Spring Boot): @dr4ke616
+ * Kotlin (Vertx): @Wooyme
* NodeJS Express: @YishTish
* PHP Laravel: @renepardon
* PHP Lumen: @abcsun
diff --git a/docs/generators.md b/docs/generators.md
index 1a4cf2c2892..7cdf880edd7 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -95,7 +95,7 @@ The following generators are available:
* [jaxrs-spec](generators/jaxrs-spec)
* [kotlin-server](generators/kotlin-server)
* [kotlin-spring](generators/kotlin-spring)
-* [kotlin-vertx](generators/kotlin-vertx)
+* [kotlin-vertx (beta)](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/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
index 19863e9a67b..36fddf1812a 100644
--- 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
@@ -19,6 +19,8 @@ package org.openapitools.codegen.languages;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
+import org.openapitools.codegen.meta.GeneratorMetadata;
+import org.openapitools.codegen.meta.Stability;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,6 +53,10 @@ public class KotlinVertxServerCodegen extends AbstractKotlinCodegen {
public KotlinVertxServerCodegen() {
super();
+ generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
+ .stability(Stability.BETA)
+ .build();
+
outputFolder = "generated-code" + File.separator + "kotlin-vertx";
modelTemplateFiles.put("model.mustache", ".kt");
@@ -61,7 +67,7 @@ public class KotlinVertxServerCodegen extends AbstractKotlinCodegen {
apiTemplateFiles.clear();
apiTemplateFiles.put("api.mustache", ".kt");
apiTemplateFiles.put("apiProxy.mustache", "VertxProxyHandler.kt");
- apiTemplateFiles.put("api_verticle.mustache","Verticle.kt");
+ apiTemplateFiles.put("api_verticle.mustache", "Verticle.kt");
embeddedTemplateDir = templateDir = "kotlin-vertx-server";
apiPackage = rootPackage + ".verticle";
@@ -78,8 +84,4 @@ public class KotlinVertxServerCodegen extends AbstractKotlinCodegen {
}
- @Override
- public String escapeReservedWord(String name) {
- return name;
- }
}
diff --git a/pom.xml b/pom.xml
index a9229c74a79..74e5a30947b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1166,6 +1166,7 @@
samples/server/petstore/scala-play-server
samples/server/petstore/scalatra
samples/server/petstore/scala-finch
+ samples/server/petstore/kotlin/vertx
samples/server/petstore/kotlin-springboot
diff --git a/samples/server/petstore/kotlin/vertx/.openapi-generator-ignore b/samples/server/petstore/kotlin/vertx/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/.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/server/petstore/kotlin/vertx/.openapi-generator/VERSION b/samples/server/petstore/kotlin/vertx/.openapi-generator/VERSION
new file mode 100644
index 00000000000..0e97bd19efb
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/.openapi-generator/VERSION
@@ -0,0 +1 @@
+4.1.3-SNAPSHOT
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin/vertx/README.md b/samples/server/petstore/kotlin/vertx/README.md
new file mode 100644
index 00000000000..4e9992d66cb
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/README.md
@@ -0,0 +1,81 @@
+# org.openapitools - Kotlin Server library for OpenAPI Petstore
+
+## 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.
+
+
+ ## Documentation for API Endpoints
+
+ All URIs are relative to *http://petstore.swagger.io/v2*
+
+ Class | Method | HTTP request | Description
+ ------------ | ------------- | ------------- | -------------
+ *PetApi* | [**addPet**](docs/PetApi.md#addpet) | **POST** /pet | Add a new pet to the store
+ *PetApi* | [**deletePet**](docs/PetApi.md#deletepet) | **DELETE** /pet/{petId} | Deletes a pet
+ *PetApi* | [**findPetsByStatus**](docs/PetApi.md#findpetsbystatus) | **GET** /pet/findByStatus | Finds Pets by status
+ *PetApi* | [**findPetsByTags**](docs/PetApi.md#findpetsbytags) | **GET** /pet/findByTags | Finds Pets by tags
+ *PetApi* | [**getPetById**](docs/PetApi.md#getpetbyid) | **GET** /pet/{petId} | Find pet by ID
+ *PetApi* | [**updatePet**](docs/PetApi.md#updatepet) | **PUT** /pet | Update an existing pet
+ *PetApi* | [**updatePetWithForm**](docs/PetApi.md#updatepetwithform) | **POST** /pet/{petId} | Updates a pet in the store with form data
+ *PetApi* | [**uploadFile**](docs/PetApi.md#uploadfile) | **POST** /pet/{petId}/uploadImage | uploads an image
+ *StoreApi* | [**deleteOrder**](docs/StoreApi.md#deleteorder) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
+ *StoreApi* | [**getInventory**](docs/StoreApi.md#getinventory) | **GET** /store/inventory | Returns pet inventories by status
+ *StoreApi* | [**getOrderById**](docs/StoreApi.md#getorderbyid) | **GET** /store/order/{orderId} | Find purchase order by ID
+ *StoreApi* | [**placeOrder**](docs/StoreApi.md#placeorder) | **POST** /store/order | Place an order for a pet
+ *UserApi* | [**createUser**](docs/UserApi.md#createuser) | **POST** /user | Create user
+ *UserApi* | [**createUsersWithArrayInput**](docs/UserApi.md#createuserswitharrayinput) | **POST** /user/createWithArray | Creates list of users with given input array
+ *UserApi* | [**createUsersWithListInput**](docs/UserApi.md#createuserswithlistinput) | **POST** /user/createWithList | Creates list of users with given input array
+ *UserApi* | [**deleteUser**](docs/UserApi.md#deleteuser) | **DELETE** /user/{username} | Delete user
+ *UserApi* | [**getUserByName**](docs/UserApi.md#getuserbyname) | **GET** /user/{username} | Get user by user name
+ *UserApi* | [**loginUser**](docs/UserApi.md#loginuser) | **GET** /user/login | Logs user into the system
+ *UserApi* | [**logoutUser**](docs/UserApi.md#logoutuser) | **GET** /user/logout | Logs out current logged in user session
+ *UserApi* | [**updateUser**](docs/UserApi.md#updateuser) | **PUT** /user/{username} | Updated user
+
+
+
+ ## Documentation for Models
+
+ - [org.openapitools.server.api.model.ApiResponse](docs/ApiResponse.md)
+ - [org.openapitools.server.api.model.Category](docs/Category.md)
+ - [org.openapitools.server.api.model.Order](docs/Order.md)
+ - [org.openapitools.server.api.model.Pet](docs/Pet.md)
+ - [org.openapitools.server.api.model.Tag](docs/Tag.md)
+ - [org.openapitools.server.api.model.User](docs/User.md)
+
+
+
+## Documentation for Authorization
+
+
+ ### api_key
+
+ - **Type**: API key
+ - **API key parameter name**: api_key
+ - **Location**: HTTP header
+
+
+ ### petstore_auth
+
+ - **Type**: OAuth
+ - **Flow**: implicit
+ - **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog
+ - **Scopes**:
+ - write:pets: modify pets in your account
+ - read:pets: read your pets
+
diff --git a/samples/server/petstore/kotlin/vertx/pom.xml b/samples/server/petstore/kotlin/vertx/pom.xml
new file mode 100644
index 00000000000..c6be42bad59
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/pom.xml
@@ -0,0 +1,190 @@
+
+ 4.0.0
+
+ org.openapitools
+ openapi-kotlin-vertx-server
+ 1.0.0-SNAPSHOT
+ jar
+
+ OpenAPI Petstore
+
+
+ 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}
+ ${java.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+
+ package
+
+ shade
+
+
+
+
+
+ org.openapitools.server.api.verticle.DefaultApiVerticleKt
+
+
+
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/ApiResponse.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/ApiResponse.kt
new file mode 100644
index 00000000000..223e80919ac
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/ApiResponse.kt
@@ -0,0 +1,34 @@
+/**
+* OpenAPI Petstore
+* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+*
+* The version of the OpenAPI document: 1.0.0
+*
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
+package org.openapitools.server.api.model
+
+
+
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * Describes the result of uploading an image resource
+ * @param code
+ * @param type
+ * @param message
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class ApiResponse (
+ var code: kotlin.Int? = null,
+ var type: kotlin.String? = null,
+ var message: kotlin.String? = null
+) {
+
+}
+
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Category.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Category.kt
new file mode 100644
index 00000000000..29aaa19c2c2
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Category.kt
@@ -0,0 +1,32 @@
+/**
+* OpenAPI Petstore
+* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+*
+* The version of the OpenAPI document: 1.0.0
+*
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
+package org.openapitools.server.api.model
+
+
+
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * A category for a pet
+ * @param id
+ * @param name
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class Category (
+ var id: kotlin.Long? = null,
+ var name: kotlin.String? = null
+) {
+
+}
+
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Order.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Order.kt
new file mode 100644
index 00000000000..2d806e9e2fc
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Order.kt
@@ -0,0 +1,55 @@
+/**
+* OpenAPI Petstore
+* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+*
+* The version of the OpenAPI document: 1.0.0
+*
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
+package org.openapitools.server.api.model
+
+
+
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * An order for a pets from the pet store
+ * @param id
+ * @param petId
+ * @param quantity
+ * @param shipDate
+ * @param status Order Status
+ * @param complete
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class Order (
+ var id: kotlin.Long? = null,
+ var petId: kotlin.Long? = null,
+ var quantity: kotlin.Int? = null,
+ var shipDate: java.time.LocalDateTime? = null,
+ /* Order Status */
+ var status: Order.Status? = null,
+ var complete: kotlin.Boolean? = null
+) {
+
+ /**
+ * Order Status
+ * Values: placed,approved,delivered
+ */
+ enum class Status(val value: kotlin.String){
+
+ placed("placed"),
+
+ approved("approved"),
+
+ delivered("delivered");
+
+ }
+
+}
+
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Pet.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Pet.kt
new file mode 100644
index 00000000000..b96a3dde895
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Pet.kt
@@ -0,0 +1,61 @@
+/**
+* OpenAPI Petstore
+* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+*
+* The version of the OpenAPI document: 1.0.0
+*
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
+package org.openapitools.server.api.model
+
+import org.openapitools.server.api.model.Category
+import org.openapitools.server.api.model.Tag
+
+
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * A pet for sale in the pet store
+ * @param id
+ * @param category
+ * @param name
+ * @param photoUrls
+ * @param tags
+ * @param status pet status in the store
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class Pet (
+ @SerializedName("name") private var _name: kotlin.String?,
+ @SerializedName("photoUrls") private var _photoUrls: kotlin.Array?,
+ var id: kotlin.Long? = null,
+ var category: Category? = null,
+ var tags: kotlin.Array? = null,
+ /* pet status in the store */
+ var status: Pet.Status? = null
+) {
+
+ /**
+ * pet status in the store
+ * Values: available,pending,sold
+ */
+ enum class Status(val value: kotlin.String){
+
+ available("available"),
+
+ pending("pending"),
+
+ sold("sold");
+
+ }
+
+ var name get() = _name ?: throw IllegalArgumentException("name is required")
+ set(value){ _name = value }
+ var photoUrls get() = _photoUrls ?: throw IllegalArgumentException("photoUrls is required")
+ set(value){ _photoUrls = value }
+}
+
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Tag.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Tag.kt
new file mode 100644
index 00000000000..359a53af609
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/Tag.kt
@@ -0,0 +1,32 @@
+/**
+* OpenAPI Petstore
+* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+*
+* The version of the OpenAPI document: 1.0.0
+*
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
+package org.openapitools.server.api.model
+
+
+
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * A tag for a pet
+ * @param id
+ * @param name
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class Tag (
+ var id: kotlin.Long? = null,
+ var name: kotlin.String? = null
+) {
+
+}
+
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/User.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/User.kt
new file mode 100644
index 00000000000..791d0b88233
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/model/User.kt
@@ -0,0 +1,45 @@
+/**
+* OpenAPI Petstore
+* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+*
+* The version of the OpenAPI document: 1.0.0
+*
+*
+* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+* https://openapi-generator.tech
+* Do not edit the class manually.
+*/
+package org.openapitools.server.api.model
+
+
+
+import com.google.gson.annotations.SerializedName
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+/**
+ * A User who is purchasing from the pet store
+ * @param id
+ * @param username
+ * @param firstName
+ * @param lastName
+ * @param email
+ * @param password
+ * @param phone
+ * @param userStatus User Status
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class User (
+ var id: kotlin.Long? = null,
+ var username: kotlin.String? = null,
+ var firstName: kotlin.String? = null,
+ var lastName: kotlin.String? = null,
+ var email: kotlin.String? = null,
+ var password: kotlin.String? = null,
+ var phone: kotlin.String? = null,
+ /* User Status */
+ var userStatus: kotlin.Int? = null
+) {
+
+}
+
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApi.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApi.kt
new file mode 100644
index 00000000000..07f92471774
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApi.kt
@@ -0,0 +1,70 @@
+package org.openapitools.server.api.verticle
+
+import org.openapitools.server.api.model.ApiResponse
+import org.openapitools.server.api.model.Pet
+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 PetApi {
+ fun init(vertx:Vertx,config:JsonObject)
+ /* addPet
+ * Add a new pet to the store */
+ suspend fun addPet(body:Pet?,context:OperationRequest):Response
+ /* deletePet
+ * Deletes a pet */
+ suspend fun deletePet(petId:kotlin.Long?,apiKey:kotlin.String?,context:OperationRequest):Response
+ /* findPetsByStatus
+ * Finds Pets by status */
+ suspend fun findPetsByStatus(status:kotlin.Array?,context:OperationRequest):Response>
+ /* findPetsByTags
+ * Finds Pets by tags */
+ suspend fun findPetsByTags(tags:kotlin.Array?,context:OperationRequest):Response>
+ /* getPetById
+ * Find pet by ID */
+ suspend fun getPetById(petId:kotlin.Long?,context:OperationRequest):Response
+ /* updatePet
+ * Update an existing pet */
+ suspend fun updatePet(body:Pet?,context:OperationRequest):Response
+ /* updatePetWithForm
+ * Updates a pet in the store with form data */
+ suspend fun updatePetWithForm(petId:kotlin.Long?,name:kotlin.String?,status:kotlin.String?,context:OperationRequest):Response
+ /* uploadFile
+ * uploads an image */
+ suspend fun uploadFile(petId:kotlin.Long?,additionalMetadata:kotlin.String?,file:kotlin.collections.List?,context:OperationRequest):Response
+ companion object {
+ const val address = "PetApi-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 PetApi::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(PetApi::class.java, address)
+ return routerFactory
+ }
+ }
+}
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApiVerticle.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApiVerticle.kt
new file mode 100644
index 00000000000..ea5e7b5f4f1
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApiVerticle.kt
@@ -0,0 +1,19 @@
+package org.openapitools.server.api.verticle
+import io.vertx.core.Vertx
+import io.vertx.core.AbstractVerticle
+import io.vertx.serviceproxy.ServiceBinder
+
+fun main(){
+ Vertx.vertx().deployVerticle(PetApiVerticle())
+}
+
+class PetApiVerticle:AbstractVerticle() {
+
+ override fun start() {
+ val instance = (javaClass.classLoader.loadClass("org.openapitools.server.api.verticle.PetApiImpl").newInstance() as PetApi)
+ instance.init(vertx,config())
+ ServiceBinder(vertx)
+ .setAddress(PetApi.address)
+ .register(PetApi::class.java,instance)
+ }
+}
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApiVertxProxyHandler.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApiVertxProxyHandler.kt
new file mode 100644
index 00000000000..6d4fcafa98b
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/PetApiVertxProxyHandler.kt
@@ -0,0 +1,214 @@
+package org.openapitools.server.api.verticle
+
+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
+import org.openapitools.server.api.model.ApiResponse
+import org.openapitools.server.api.model.Pet
+
+class PetApiVertxProxyHandler(private val vertx: Vertx, private val service: PetApi, 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) {
+
+ "addPet" -> {
+ val params = context.params
+ val bodyParam = ApiHandlerUtils.searchJsonObjectInJson(params,"body")
+ if (bodyParam == null) {
+ throw IllegalArgumentException("body is required")
+ }
+ val body = Gson().fromJson(bodyParam.encode(), Pet::class.java)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.addPet(body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "deletePet" -> {
+ val params = context.params
+ val petId = ApiHandlerUtils.searchLongInJson(params,"petId")
+ if(petId == null){
+ throw IllegalArgumentException("petId is required")
+ }
+ val apiKey = ApiHandlerUtils.searchStringInJson(params,"api_key")
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.deletePet(petId,apiKey,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "findPetsByStatus" -> {
+ val params = context.params
+ val statusParam = ApiHandlerUtils.searchJsonArrayInJson(params,"status")
+ if(statusParam == null){
+ throw IllegalArgumentException("status is required")
+ }
+ val status:kotlin.Array = Gson().fromJson(statusParam.encode()
+ , object : TypeToken>(){}.type)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.findPetsByStatus(status,context)
+ val payload = JsonArray(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "findPetsByTags" -> {
+ val params = context.params
+ val tagsParam = ApiHandlerUtils.searchJsonArrayInJson(params,"tags")
+ if(tagsParam == null){
+ throw IllegalArgumentException("tags is required")
+ }
+ val tags:kotlin.Array = Gson().fromJson(tagsParam.encode()
+ , object : TypeToken>(){}.type)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.findPetsByTags(tags,context)
+ val payload = JsonArray(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "getPetById" -> {
+ val params = context.params
+ val petId = ApiHandlerUtils.searchLongInJson(params,"petId")
+ if(petId == null){
+ throw IllegalArgumentException("petId is required")
+ }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.getPetById(petId,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "updatePet" -> {
+ val params = context.params
+ val bodyParam = ApiHandlerUtils.searchJsonObjectInJson(params,"body")
+ if (bodyParam == null) {
+ throw IllegalArgumentException("body is required")
+ }
+ val body = Gson().fromJson(bodyParam.encode(), Pet::class.java)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.updatePet(body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "updatePetWithForm" -> {
+ val params = context.params
+ val petId = ApiHandlerUtils.searchLongInJson(params,"petId")
+ if(petId == null){
+ throw IllegalArgumentException("petId is required")
+ }
+ val name = ApiHandlerUtils.searchStringInJson(params,"name")
+ val status = ApiHandlerUtils.searchStringInJson(params,"status")
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.updatePetWithForm(petId,name,status,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "uploadFile" -> {
+ val params = context.params
+ val petId = ApiHandlerUtils.searchLongInJson(params,"petId")
+ if(petId == null){
+ throw IllegalArgumentException("petId is required")
+ }
+ val additionalMetadata = ApiHandlerUtils.searchStringInJson(params,"additionalMetadata")
+ val fileParam = context.extra.getJsonArray("files")
+ val file = fileParam?.map{ java.io.File(it as String) }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.uploadFile(petId,additionalMetadata,file,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ }
+ }catch (t: Throwable) {
+ msg.reply(ServiceException(500, t.message))
+ throw t
+ }
+ }
+}
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApi.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApi.kt
new file mode 100644
index 00000000000..ac40c5a4527
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApi.kt
@@ -0,0 +1,57 @@
+package org.openapitools.server.api.verticle
+
+import org.openapitools.server.api.model.Order
+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 StoreApi {
+ fun init(vertx:Vertx,config:JsonObject)
+ /* deleteOrder
+ * Delete purchase order by ID */
+ suspend fun deleteOrder(orderId:kotlin.String?,context:OperationRequest):Response
+ /* getInventory
+ * Returns pet inventories by status */
+ suspend fun getInventory(context:OperationRequest):Response>
+ /* getOrderById
+ * Find purchase order by ID */
+ suspend fun getOrderById(orderId:kotlin.Long?,context:OperationRequest):Response
+ /* placeOrder
+ * Place an order for a pet */
+ suspend fun placeOrder(body:Order?,context:OperationRequest):Response
+ companion object {
+ const val address = "StoreApi-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 StoreApi::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(StoreApi::class.java, address)
+ return routerFactory
+ }
+ }
+}
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApiVerticle.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApiVerticle.kt
new file mode 100644
index 00000000000..dd885532237
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApiVerticle.kt
@@ -0,0 +1,19 @@
+package org.openapitools.server.api.verticle
+import io.vertx.core.Vertx
+import io.vertx.core.AbstractVerticle
+import io.vertx.serviceproxy.ServiceBinder
+
+fun main(){
+ Vertx.vertx().deployVerticle(StoreApiVerticle())
+}
+
+class StoreApiVerticle:AbstractVerticle() {
+
+ override fun start() {
+ val instance = (javaClass.classLoader.loadClass("org.openapitools.server.api.verticle.StoreApiImpl").newInstance() as StoreApi)
+ instance.init(vertx,config())
+ ServiceBinder(vertx)
+ .setAddress(StoreApi.address)
+ .register(StoreApi::class.java,instance)
+ }
+}
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApiVertxProxyHandler.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApiVertxProxyHandler.kt
new file mode 100644
index 00000000000..985b9249f56
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/StoreApiVertxProxyHandler.kt
@@ -0,0 +1,125 @@
+package org.openapitools.server.api.verticle
+
+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
+import org.openapitools.server.api.model.Order
+
+class StoreApiVertxProxyHandler(private val vertx: Vertx, private val service: StoreApi, 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) {
+
+ "deleteOrder" -> {
+ val params = context.params
+ val orderId = ApiHandlerUtils.searchStringInJson(params,"orderId")
+ if(orderId == null){
+ throw IllegalArgumentException("orderId is required")
+ }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.deleteOrder(orderId,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "getInventory" -> {
+ }
+
+ "getOrderById" -> {
+ val params = context.params
+ val orderId = ApiHandlerUtils.searchLongInJson(params,"orderId")
+ if(orderId == null){
+ throw IllegalArgumentException("orderId is required")
+ }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.getOrderById(orderId,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "placeOrder" -> {
+ val params = context.params
+ val bodyParam = ApiHandlerUtils.searchJsonObjectInJson(params,"body")
+ if (bodyParam == null) {
+ throw IllegalArgumentException("body is required")
+ }
+ val body = Gson().fromJson(bodyParam.encode(), Order::class.java)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.placeOrder(body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ }
+ }catch (t: Throwable) {
+ msg.reply(ServiceException(500, t.message))
+ throw t
+ }
+ }
+}
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApi.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApi.kt
new file mode 100644
index 00000000000..e48a7273b2a
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApi.kt
@@ -0,0 +1,69 @@
+package org.openapitools.server.api.verticle
+
+import org.openapitools.server.api.model.User
+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 UserApi {
+ fun init(vertx:Vertx,config:JsonObject)
+ /* createUser
+ * Create user */
+ suspend fun createUser(body:User?,context:OperationRequest):Response
+ /* createUsersWithArrayInput
+ * Creates list of users with given input array */
+ suspend fun createUsersWithArrayInput(body:kotlin.Array?,context:OperationRequest):Response
+ /* createUsersWithListInput
+ * Creates list of users with given input array */
+ suspend fun createUsersWithListInput(body:kotlin.Array?,context:OperationRequest):Response
+ /* deleteUser
+ * Delete user */
+ suspend fun deleteUser(username:kotlin.String?,context:OperationRequest):Response
+ /* getUserByName
+ * Get user by user name */
+ suspend fun getUserByName(username:kotlin.String?,context:OperationRequest):Response
+ /* loginUser
+ * Logs user into the system */
+ suspend fun loginUser(username:kotlin.String?,password:kotlin.String?,context:OperationRequest):Response
+ /* logoutUser
+ * Logs out current logged in user session */
+ suspend fun logoutUser(context:OperationRequest):Response
+ /* updateUser
+ * Updated user */
+ suspend fun updateUser(username:kotlin.String?,body:User?,context:OperationRequest):Response
+ companion object {
+ const val address = "UserApi-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 UserApi::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(UserApi::class.java, address)
+ return routerFactory
+ }
+ }
+}
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApiVerticle.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApiVerticle.kt
new file mode 100644
index 00000000000..2b121c28bb1
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApiVerticle.kt
@@ -0,0 +1,19 @@
+package org.openapitools.server.api.verticle
+import io.vertx.core.Vertx
+import io.vertx.core.AbstractVerticle
+import io.vertx.serviceproxy.ServiceBinder
+
+fun main(){
+ Vertx.vertx().deployVerticle(UserApiVerticle())
+}
+
+class UserApiVerticle:AbstractVerticle() {
+
+ override fun start() {
+ val instance = (javaClass.classLoader.loadClass("org.openapitools.server.api.verticle.UserApiImpl").newInstance() as UserApi)
+ instance.init(vertx,config())
+ ServiceBinder(vertx)
+ .setAddress(UserApi.address)
+ .register(UserApi::class.java,instance)
+ }
+}
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApiVertxProxyHandler.kt b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApiVertxProxyHandler.kt
new file mode 100644
index 00000000000..beee4405bee
--- /dev/null
+++ b/samples/server/petstore/kotlin/vertx/src/main/kotlin/org/openapitools/server/api/verticle/UserApiVertxProxyHandler.kt
@@ -0,0 +1,202 @@
+package org.openapitools.server.api.verticle
+
+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
+import org.openapitools.server.api.model.User
+
+class UserApiVertxProxyHandler(private val vertx: Vertx, private val service: UserApi, 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) {
+
+ "createUser" -> {
+ val params = context.params
+ val bodyParam = ApiHandlerUtils.searchJsonObjectInJson(params,"body")
+ if (bodyParam == null) {
+ throw IllegalArgumentException("body is required")
+ }
+ val body = Gson().fromJson(bodyParam.encode(), User::class.java)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.createUser(body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "createUsersWithArrayInput" -> {
+ val params = context.params
+ val bodyParam = ApiHandlerUtils.searchJsonArrayInJson(params,"body")
+ if(bodyParam == null){
+ throw IllegalArgumentException("body is required")
+ }
+ val body:kotlin.Array = Gson().fromJson(bodyParam.encode()
+ , object : TypeToken>(){}.type)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.createUsersWithArrayInput(body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "createUsersWithListInput" -> {
+ val params = context.params
+ val bodyParam = ApiHandlerUtils.searchJsonArrayInJson(params,"body")
+ if(bodyParam == null){
+ throw IllegalArgumentException("body is required")
+ }
+ val body:kotlin.Array = Gson().fromJson(bodyParam.encode()
+ , object : TypeToken>(){}.type)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.createUsersWithListInput(body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "deleteUser" -> {
+ val params = context.params
+ val username = ApiHandlerUtils.searchStringInJson(params,"username")
+ if(username == null){
+ throw IllegalArgumentException("username is required")
+ }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.deleteUser(username,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "getUserByName" -> {
+ val params = context.params
+ val username = ApiHandlerUtils.searchStringInJson(params,"username")
+ if(username == null){
+ throw IllegalArgumentException("username is required")
+ }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.getUserByName(username,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "loginUser" -> {
+ val params = context.params
+ val username = ApiHandlerUtils.searchStringInJson(params,"username")
+ if(username == null){
+ throw IllegalArgumentException("username is required")
+ }
+ val password = ApiHandlerUtils.searchStringInJson(params,"password")
+ if(password == null){
+ throw IllegalArgumentException("password is required")
+ }
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.loginUser(username,password,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ "logoutUser" -> {
+ }
+
+ "updateUser" -> {
+ val params = context.params
+ val username = ApiHandlerUtils.searchStringInJson(params,"username")
+ if(username == null){
+ throw IllegalArgumentException("username is required")
+ }
+ val bodyParam = ApiHandlerUtils.searchJsonObjectInJson(params,"body")
+ if (bodyParam == null) {
+ throw IllegalArgumentException("body is required")
+ }
+ val body = Gson().fromJson(bodyParam.encode(), User::class.java)
+ GlobalScope.launch(vertx.dispatcher()){
+ val result = service.updateUser(username,body,context)
+ val payload = JsonObject(Json.encode(result.payload)).toBuffer()
+ val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers)
+ msg.reply(res.toJson())
+ }.invokeOnCompletion{
+ it?.let{ throw it }
+ }
+ }
+
+ }
+ }catch (t: Throwable) {
+ msg.reply(ServiceException(500, t.message))
+ throw t
+ }
+ }
+}