diff --git a/bin/kotlin-client-all.sh b/bin/kotlin-client-all.sh
index c27d1dcbcc2..f62755cf000 100755
--- a/bin/kotlin-client-all.sh
+++ b/bin/kotlin-client-all.sh
@@ -9,3 +9,4 @@
./bin/kotlin-client-string.sh
./bin/kotlin-client-threetenbp.sh
./bin/kotlin-client-nullable.sh
+./bin/kotlin-client-retrofit2.sh
diff --git a/bin/kotlin-client-retrofit2.sh b/bin/kotlin-client-retrofit2.sh
new file mode 100755
index 00000000000..52149c2e633
--- /dev/null
+++ b/bin/kotlin-client-retrofit2.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 -B 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 -t modules/openapi-generator/src/main/resources/kotlin-client -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g kotlin --artifact-id kotlin-petstore-retrofit2 --library retrofit2 -o samples/client/petstore/kotlin-retrofit2 $@"
+
+java ${JAVA_OPTS} -jar ${executable} ${ags}
\ No newline at end of file
diff --git a/docs/generators/kotlin.md b/docs/generators/kotlin.md
index d64fd3964ff..86fbf23e5d0 100644
--- a/docs/generators/kotlin.md
+++ b/docs/generators/kotlin.md
@@ -18,4 +18,4 @@ sidebar_label: kotlin
|modelMutable|Create mutable models| |false|
|dateLibrary|Option. Date library to use|
- **string**
- String
- **java8**
- Java 8 native JSR310 (jvm only)
- **threetenbp**
- Threetenbp (jvm only)
|java8|
|collectionType|Option. Collection type to use|- **array**
- kotlin.Array
- **list**
- kotlin.collections.List
|array|
-|library|Library template (sub-template) to use|- **jvm-okhttp4**
- [DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0.
- **jvm-okhttp3**
- Platform: Java Virtual Machine. HTTP client: OkHttp 3.12.4 (Android 2.3+ and Java 7+). JSON processing: Moshi 1.8.0.
- **multiplatform**
- Platform: Kotlin multiplatform. HTTP client: Ktor 1.2.4. JSON processing: Kotlinx Serialization: 0.12.0.
|jvm-okhttp4|
+|library|Library template (sub-template) to use|- **jvm-okhttp4**
- [DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0.
- **jvm-okhttp3**
- Platform: Java Virtual Machine. HTTP client: OkHttp 3.12.4 (Android 2.3+ and Java 7+). JSON processing: Moshi 1.8.0.
- **retrofit2**
- Platform: Java Virtual Machine. HTTP client: Retrofit 2.6.2.
- **multiplatform**
- Platform: Kotlin multiplatform. HTTP client: Ktor 1.2.4. JSON processing: Kotlinx Serialization: 0.12.0.
|jvm-okhttp4|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
index 2f463f51a57..3d3e7fbe748 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
@@ -29,6 +29,7 @@ import org.openapitools.codegen.SupportingFile;
import java.io.File;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -38,6 +39,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
protected static final String JVM = "jvm";
protected static final String JVM_OKHTTP4 = "jvm-okhttp4";
protected static final String JVM_OKHTTP3 = "jvm-okhttp3";
+ protected static final String RETROFIT2 = "retrofit2";
protected static final String MULTIPLATFORM = "multiplatform";
public static final String DATE_LIBRARY = "dateLibrary";
@@ -112,6 +114,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
supportedLibraries.put(JVM_OKHTTP4, "[DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0.");
supportedLibraries.put(JVM_OKHTTP3, "Platform: Java Virtual Machine. HTTP client: OkHttp 3.12.4 (Android 2.3+ and Java 7+). JSON processing: Moshi 1.8.0.");
+ supportedLibraries.put(RETROFIT2, "Platform: Java Virtual Machine. HTTP client: Retrofit 2.6.2.");
supportedLibraries.put(MULTIPLATFORM, "Platform: Kotlin multiplatform. HTTP client: Ktor 1.2.4. JSON processing: Kotlinx Serialization: 0.12.0.");
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "Library template (sub-template) to use");
@@ -157,115 +160,24 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
setDateLibrary(additionalProperties.get(DATE_LIBRARY).toString());
}
- // common (jvm/multiplatform) supporting files
- supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
- supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
- supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
- supportingFiles.add(new SupportingFile("infrastructure/ApiClient.kt.mustache", infrastructureFolder, "ApiClient.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/ApiAbstractions.kt.mustache", infrastructureFolder, "ApiAbstractions.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/RequestConfig.kt.mustache", infrastructureFolder, "RequestConfig.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/RequestMethod.kt.mustache", infrastructureFolder, "RequestMethod.kt"));
+ commonSupportingFiles();
- if (isJVMLibrary()) {
- additionalProperties.put(JVM, true);
-
- if (JVM_OKHTTP4.equals(getLibrary())) {
- additionalProperties.put(JVM_OKHTTP4, true);
- } else if (JVM_OKHTTP3.equals(getLibrary())) {
- additionalProperties.put(JVM_OKHTTP3, true);
- }
-
- supportedLibraries.put(JVM, "A workaround to use the same template folder for both 'jvm-okhttp3' and 'jvm-okhttp4'.");
- setLibrary(JVM);
-
- // jvm specific supporting files
- supportingFiles.add(new SupportingFile("infrastructure/ApplicationDelegates.kt.mustache", infrastructureFolder, "ApplicationDelegates.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/Errors.kt.mustache", infrastructureFolder, "Errors.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/ResponseExtensions.kt.mustache", infrastructureFolder, "ResponseExtensions.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/Serializer.kt.mustache", infrastructureFolder, "Serializer.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/ApiInfrastructureResponse.kt.mustache", infrastructureFolder, "ApiInfrastructureResponse.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/ByteArrayAdapter.kt.mustache", infrastructureFolder, "ByteArrayAdapter.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/LocalDateAdapter.kt.mustache", infrastructureFolder, "LocalDateAdapter.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/LocalDateTimeAdapter.kt.mustache", infrastructureFolder, "LocalDateTimeAdapter.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/UUIDAdapter.kt.mustache", infrastructureFolder, "UUIDAdapter.kt"));
- if (getSerializationLibrary() == SERIALIZATION_LIBRARY_TYPE.gson) {
- supportingFiles.add(new SupportingFile("infrastructure/DateAdapter.kt.mustache", infrastructureFolder,
- "DateAdapter.kt"));
- }
-
- } else if (MULTIPLATFORM.equals(getLibrary())) {
- additionalProperties.put(MULTIPLATFORM, true);
- setDateLibrary(DateLibrary.STRING.value);
-
- // multiplatform default includes
- defaultIncludes.add("io.ktor.client.request.forms.InputProvider");
- defaultIncludes.add(packageName + ".infrastructure.Base64ByteArray");
- defaultIncludes.add(packageName + ".infrastructure.OctetByteArray");
-
- // multiplatform type mapping
- typeMapping.put("number", "kotlin.Double");
- typeMapping.put("file", "OctetByteArray");
- typeMapping.put("binary", "OctetByteArray");
- typeMapping.put("ByteArray", "Base64ByteArray");
- typeMapping.put("object", "kotlin.String"); // kotlin.Any not serializable
-
- // multiplatform import mapping
- importMapping.put("BigDecimal", "kotlin.Double");
- importMapping.put("UUID", "kotlin.String");
- importMapping.put("URI", "kotlin.String");
- importMapping.put("InputProvider", "io.ktor.client.request.forms.InputProvider");
- importMapping.put("File", packageName + ".infrastructure.OctetByteArray");
- importMapping.put("Timestamp", "kotlin.String");
- importMapping.put("LocalDateTime", "kotlin.String");
- importMapping.put("LocalDate", "kotlin.String");
- importMapping.put("LocalTime", "kotlin.String");
- importMapping.put("Base64ByteArray", packageName + ".infrastructure.Base64ByteArray");
- importMapping.put("OctetByteArray", packageName + ".infrastructure.OctetByteArray");
-
- // multiplatform specific supporting files
- supportingFiles.add(new SupportingFile("infrastructure/Base64ByteArray.kt.mustache", infrastructureFolder, "Base64ByteArray.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/Bytes.kt.mustache", infrastructureFolder, "Bytes.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/HttpResponse.kt.mustache", infrastructureFolder, "HttpResponse.kt"));
- supportingFiles.add(new SupportingFile("infrastructure/OctetByteArray.kt.mustache", infrastructureFolder, "OctetByteArray.kt"));
-
- // multiplatform specific auth
- final String authFolder = (sourceFolder + File.separator + packageName + File.separator + "auth").replace(".", "/");
- supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.kt.mustache", authFolder, "ApiKeyAuth.kt"));
- supportingFiles.add(new SupportingFile("auth/Authentication.kt.mustache", authFolder, "Authentication.kt"));
- supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.kt.mustache", authFolder, "HttpBasicAuth.kt"));
- supportingFiles.add(new SupportingFile("auth/HttpBearerAuth.kt.mustache", authFolder, "HttpBearerAuth.kt"));
- supportingFiles.add(new SupportingFile("auth/OAuth.kt.mustache", authFolder, "OAuth.kt"));
-
- // multiplatform specific testing files
- supportingFiles.add(new SupportingFile("commonTest/Coroutine.kt.mustache", "src/commonTest/kotlin/util", "Coroutine.kt"));
- supportingFiles.add(new SupportingFile("iosTest/Coroutine.kt.mustache", "src/iosTest/kotlin/util", "Coroutine.kt"));
- supportingFiles.add(new SupportingFile("jsTest/Coroutine.kt.mustache", "src/jsTest/kotlin/util", "Coroutine.kt"));
- supportingFiles.add(new SupportingFile("jvmTest/Coroutine.kt.mustache", "src/jvmTest/kotlin/util", "Coroutine.kt"));
-
- // gradle wrapper supporting files
- supportingFiles.add(new SupportingFile("gradlew.mustache", "", "gradlew"));
- supportingFiles.add(new SupportingFile("gradlew.bat.mustache", "", "gradlew.bat"));
- supportingFiles.add(new SupportingFile("gradle-wrapper.properties.mustache", "gradle.wrapper".replace(".", File.separator), "gradle-wrapper.properties"));
- supportingFiles.add(new SupportingFile("gradle-wrapper.jar", "gradle.wrapper".replace(".", File.separator), "gradle-wrapper.jar"));
+ switch (getLibrary()) {
+ case JVM_OKHTTP3:
+ case JVM_OKHTTP4:
+ processJVMLibrary(infrastructureFolder);
+ break;
+ case RETROFIT2:
+ processRetrofit2Library(infrastructureFolder);
+ break;
+ case MULTIPLATFORM:
+ processMultiplatformLibrary(infrastructureFolder);
+ break;
+ default:
+ break;
}
- // date library processing
- if (DateLibrary.THREETENBP.value.equals(dateLibrary)) {
- additionalProperties.put(DateLibrary.THREETENBP.value, true);
- typeMapping.put("date", "LocalDate");
- typeMapping.put("DateTime", "LocalDateTime");
- importMapping.put("LocalDate", "org.threeten.bp.LocalDate");
- importMapping.put("LocalDateTime", "org.threeten.bp.LocalDateTime");
- defaultIncludes.add("org.threeten.bp.LocalDate");
- defaultIncludes.add("org.threeten.bp.LocalDateTime");
- } else if (DateLibrary.STRING.value.equals(dateLibrary)) {
- typeMapping.put("date-time", "kotlin.String");
- typeMapping.put("date", "kotlin.String");
- typeMapping.put("Date", "kotlin.String");
- typeMapping.put("DateTime", "kotlin.String");
- } else if (DateLibrary.JAVA8.value.equals(dateLibrary)) {
- additionalProperties.put(DateLibrary.JAVA8.value, true);
- }
+ processDateLibrary();
if (additionalProperties.containsKey(COLLECTION_TYPE)) {
setCollectionType(additionalProperties.get(COLLECTION_TYPE).toString());
@@ -276,11 +188,157 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
typeMapping.put("list", "kotlin.collections.List");
additionalProperties.put("isList", true);
}
-
}
- private boolean isJVMLibrary() {
- return getLibrary() != null && (getLibrary().contains(JVM_OKHTTP4) || getLibrary().contains(JVM_OKHTTP3));
+ private void processDateLibrary() {
+ DateLibrary dateLibraryEnum = DateLibrary.valueOf(dateLibrary.toUpperCase(Locale.ROOT));
+ switch (dateLibraryEnum) {
+ case THREETENBP:
+ processThreeTeBpDate();
+ break;
+ case STRING:
+ processStringDate();
+ break;
+ case JAVA8:
+ processJava8Date();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processThreeTeBpDate() {
+ additionalProperties.put(DateLibrary.THREETENBP.value, true);
+ typeMapping.put("date", "LocalDate");
+ typeMapping.put("DateTime", "LocalDateTime");
+ importMapping.put("LocalDate", "org.threeten.bp.LocalDate");
+ importMapping.put("LocalDateTime", "org.threeten.bp.LocalDateTime");
+ defaultIncludes.add("org.threeten.bp.LocalDate");
+ defaultIncludes.add("org.threeten.bp.LocalDateTime");
+ }
+
+ private void processStringDate() {
+ typeMapping.put("date-time", "kotlin.String");
+ typeMapping.put("date", "kotlin.String");
+ typeMapping.put("Date", "kotlin.String");
+ typeMapping.put("DateTime", "kotlin.String");
+ }
+
+ private void processJava8Date() {
+ additionalProperties.put(DateLibrary.JAVA8.value, true);
+ }
+
+ private void processRetrofit2Library(String infrastructureFolder) {
+ additionalProperties.put(RETROFIT2, true);
+ supportingFiles.add(new SupportingFile("infrastructure/ApiClient.kt.mustache", infrastructureFolder, "ApiClient.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/CollectionFormats.kt.mustache", infrastructureFolder, "CollectionFormats.kt"));
+ addSupportingSerializerAdapters(infrastructureFolder);
+ }
+
+ private void addSupportingSerializerAdapters(final String infrastructureFolder) {
+ supportingFiles.add(new SupportingFile("infrastructure/Serializer.kt.mustache", infrastructureFolder, "Serializer.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/ByteArrayAdapter.kt.mustache", infrastructureFolder, "ByteArrayAdapter.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/LocalDateAdapter.kt.mustache", infrastructureFolder, "LocalDateAdapter.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/LocalDateTimeAdapter.kt.mustache", infrastructureFolder, "LocalDateTimeAdapter.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/UUIDAdapter.kt.mustache", infrastructureFolder, "UUIDAdapter.kt"));
+
+ if (getSerializationLibrary() == SERIALIZATION_LIBRARY_TYPE.gson) {
+ supportingFiles.add(new SupportingFile("infrastructure/DateAdapter.kt.mustache", infrastructureFolder,
+ "DateAdapter.kt"));
+ }
+ }
+
+ private void processJVMLibrary(final String infrastructureFolder) {
+ commonJvmMultiplatformSupportingFiles(infrastructureFolder);
+ addSupportingSerializerAdapters(infrastructureFolder);
+
+ additionalProperties.put(JVM, true);
+
+ if (JVM_OKHTTP4.equals(getLibrary())) {
+ additionalProperties.put(JVM_OKHTTP4, true);
+ } else if (JVM_OKHTTP3.equals(getLibrary())) {
+ additionalProperties.put(JVM_OKHTTP3, true);
+ }
+
+ supportedLibraries.put(JVM, "A workaround to use the same template folder for both 'jvm-okhttp3' and 'jvm-okhttp4'.");
+ setLibrary(JVM);
+
+ // jvm specific supporting files
+ supportingFiles.add(new SupportingFile("infrastructure/ApplicationDelegates.kt.mustache", infrastructureFolder, "ApplicationDelegates.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/Errors.kt.mustache", infrastructureFolder, "Errors.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/ResponseExtensions.kt.mustache", infrastructureFolder, "ResponseExtensions.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/ApiInfrastructureResponse.kt.mustache", infrastructureFolder, "ApiInfrastructureResponse.kt"));
+ }
+
+ private void processMultiplatformLibrary(final String infrastructureFolder) {
+ commonJvmMultiplatformSupportingFiles(infrastructureFolder);
+ additionalProperties.put(MULTIPLATFORM, true);
+ setDateLibrary(DateLibrary.STRING.value);
+
+ // multiplatform default includes
+ defaultIncludes.add("io.ktor.client.request.forms.InputProvider");
+ defaultIncludes.add(packageName + ".infrastructure.Base64ByteArray");
+ defaultIncludes.add(packageName + ".infrastructure.OctetByteArray");
+
+ // multiplatform type mapping
+ typeMapping.put("number", "kotlin.Double");
+ typeMapping.put("file", "OctetByteArray");
+ typeMapping.put("binary", "OctetByteArray");
+ typeMapping.put("ByteArray", "Base64ByteArray");
+ typeMapping.put("object", "kotlin.String"); // kotlin.Any not serializable
+
+ // multiplatform import mapping
+ importMapping.put("BigDecimal", "kotlin.Double");
+ importMapping.put("UUID", "kotlin.String");
+ importMapping.put("URI", "kotlin.String");
+ importMapping.put("InputProvider", "io.ktor.client.request.forms.InputProvider");
+ importMapping.put("File", packageName + ".infrastructure.OctetByteArray");
+ importMapping.put("Timestamp", "kotlin.String");
+ importMapping.put("LocalDateTime", "kotlin.String");
+ importMapping.put("LocalDate", "kotlin.String");
+ importMapping.put("LocalTime", "kotlin.String");
+ importMapping.put("Base64ByteArray", packageName + ".infrastructure.Base64ByteArray");
+ importMapping.put("OctetByteArray", packageName + ".infrastructure.OctetByteArray");
+
+ // multiplatform specific supporting files
+ supportingFiles.add(new SupportingFile("infrastructure/Base64ByteArray.kt.mustache", infrastructureFolder, "Base64ByteArray.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/Bytes.kt.mustache", infrastructureFolder, "Bytes.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/HttpResponse.kt.mustache", infrastructureFolder, "HttpResponse.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/OctetByteArray.kt.mustache", infrastructureFolder, "OctetByteArray.kt"));
+
+ // multiplatform specific auth
+ final String authFolder = (sourceFolder + File.separator + packageName + File.separator + "auth").replace(".", "/");
+ supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.kt.mustache", authFolder, "ApiKeyAuth.kt"));
+ supportingFiles.add(new SupportingFile("auth/Authentication.kt.mustache", authFolder, "Authentication.kt"));
+ supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.kt.mustache", authFolder, "HttpBasicAuth.kt"));
+ supportingFiles.add(new SupportingFile("auth/HttpBearerAuth.kt.mustache", authFolder, "HttpBearerAuth.kt"));
+ supportingFiles.add(new SupportingFile("auth/OAuth.kt.mustache", authFolder, "OAuth.kt"));
+
+ // multiplatform specific testing files
+ supportingFiles.add(new SupportingFile("commonTest/Coroutine.kt.mustache", "src/commonTest/kotlin/util", "Coroutine.kt"));
+ supportingFiles.add(new SupportingFile("iosTest/Coroutine.kt.mustache", "src/iosTest/kotlin/util", "Coroutine.kt"));
+ supportingFiles.add(new SupportingFile("jsTest/Coroutine.kt.mustache", "src/jsTest/kotlin/util", "Coroutine.kt"));
+ supportingFiles.add(new SupportingFile("jvmTest/Coroutine.kt.mustache", "src/jvmTest/kotlin/util", "Coroutine.kt"));
+
+ // gradle wrapper supporting files
+ supportingFiles.add(new SupportingFile("gradlew.mustache", "", "gradlew"));
+ supportingFiles.add(new SupportingFile("gradlew.bat.mustache", "", "gradlew.bat"));
+ supportingFiles.add(new SupportingFile("gradle-wrapper.properties.mustache", "gradle.wrapper".replace(".", File.separator), "gradle-wrapper.properties"));
+ supportingFiles.add(new SupportingFile("gradle-wrapper.jar", "gradle.wrapper".replace(".", File.separator), "gradle-wrapper.jar"));
+ }
+
+
+ private void commonJvmMultiplatformSupportingFiles(String infrastructureFolder) {
+ supportingFiles.add(new SupportingFile("infrastructure/ApiClient.kt.mustache", infrastructureFolder, "ApiClient.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/ApiAbstractions.kt.mustache", infrastructureFolder, "ApiAbstractions.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/RequestConfig.kt.mustache", infrastructureFolder, "RequestConfig.kt"));
+ supportingFiles.add(new SupportingFile("infrastructure/RequestMethod.kt.mustache", infrastructureFolder, "RequestMethod.kt"));
+ }
+
+ private void commonSupportingFiles() {
+ supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
+ supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
+ supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
}
@Override
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache
index 6cafc6f241f..c8d924f81cd 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/build.gradle.mustache
@@ -8,6 +8,9 @@ wrapper {
buildscript {
ext.kotlin_version = '1.3.61'
+ {{#retrofit2}}
+ ext.retrofitVersion = '2.6.2'
+ {{/retrofit2}}
repositories {
mavenCentral()
@@ -38,10 +41,10 @@ dependencies {
compile "com.squareup.moshi:moshi-kotlin:1.9.2"
{{/moshiCodeGen}}
compile "com.squareup.moshi:moshi-adapters:1.9.2"
- {{#moshiCodeGen}}
+ {{#moshiCodeGen}}
compile "com.squareup.moshi:moshi:1.9.2"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.9.2"
- {{/moshiCodeGen}}
+ {{/moshiCodeGen}}
{{/moshi}}
{{#gson}}
compile "com.google.code.gson:gson:2.8.6"
@@ -55,5 +58,15 @@ dependencies {
{{#threetenbp}}
compile "org.threeten:threetenbp:1.4.0"
{{/threetenbp}}
+ {{#retrofit2}}
+ compile "com.squareup.retrofit2:retrofit:$retrofitVersion"
+ {{#gson}}
+ compile "com.squareup.retrofit2:converter-gson:$retrofitVersion"
+ {{/gson}}
+ {{#moshi}}
+ compile "com.squareup.retrofit2:converter-moshi:$retrofitVersion"
+ {{/moshi}}
+ compile "com.squareup.retrofit2:converter-scalars:$retrofitVersion"
+ {{/retrofit2}}
testCompile "io.kotlintest:kotlintest-runner-junit5:3.1.0"
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache
index 5cd71c1559c..df8e22b9f84 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache
@@ -1,4 +1,4 @@
-{{#jvm}}
+{{^multiplatform}}
{{#gson}}
import com.google.gson.annotations.SerializedName
{{/gson}}
@@ -13,7 +13,7 @@ import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
{{/parcelizeModels}}
-{{/jvm}}
+{{/multiplatform}}
{{#multiplatform}}
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
@@ -59,14 +59,14 @@ import java.io.Serializable
{{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{{nameInCamelCase}}}(val value: {{#isListContainer}}{{{ nestedType }}}{{/isListContainer}}{{^isListContainer}}{{{dataType}}}{{/isListContainer}}){
{{#allowableValues}}
{{#enumVars}}
- {{#jvm}}
+ {{^multiplatform}}
{{#moshi}}
@Json(name = {{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/moshi}}
{{#gson}}
@SerializedName(value={{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/gson}}
- {{/jvm}}
+ {{/multiplatform}}
{{#multiplatform}}
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/multiplatform}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache
index ff0fc3a4ce5..3a8d2871db6 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache
@@ -1,12 +1,12 @@
{{#description}}
/* {{{description}}} */
{{/description}}
- {{#jvm}}
+ {{^multiplatform}}
{{#moshi}}
@Json(name = "{{{vendorExtensions.x-base-name-literal}}}")
{{/moshi}}
{{#gson}}
@SerializedName("{{{vendorExtensions.x-base-name-literal}}}")
{{/gson}}
- {{/jvm}}
+ {{/multiplatform}}
{{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") {{/multiplatform}}{{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isListContainer}}{{#isList}}kotlin.collections.List{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{classname}}.{{{nameInCamelCase}}}>{{/isListContainer}}{{^isListContainer}}{{classname}}.{{{nameInCamelCase}}}{{/isListContainer}}{{/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-client/data_class_req_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache
index c7a068e7ca3..ca645e26c85 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache
@@ -1,12 +1,12 @@
{{#description}}
/* {{{description}}} */
{{/description}}
- {{#jvm}}
+ {{^multiplatform}}
{{#moshi}}
@Json(name = "{{{vendorExtensions.x-base-name-literal}}}")
{{/moshi}}
{{#gson}}
@SerializedName("{{{vendorExtensions.x-base-name-literal}}}")
{{/gson}}
- {{/jvm}}
+ {{/multiplatform}}
{{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") @Required {{/multiplatform}}{{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isListContainer}}{{#isList}}kotlin.collections.List{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{classname}}.{{{nameInCamelCase}}}>{{/isListContainer}}{{^isListContainer}}{{classname}}.{{{nameInCamelCase}}}{{/isListContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/enum_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/enum_class.mustache
index 9c848451846..73113186c51 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/enum_class.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/enum_class.mustache
@@ -1,11 +1,11 @@
-{{#jvm}}
+{{^multiplatform}}
{{#gson}}
import com.google.gson.annotations.SerializedName
{{/gson}}
{{#moshi}}
import com.squareup.moshi.Json
{{/moshi}}
-{{/jvm}}
+{{/multiplatform}}
{{#multiplatform}}
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
@@ -19,14 +19,14 @@ import kotlinx.serialization.internal.CommonEnumSerializer
{{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{classname}}(val value: {{{dataType}}}){
{{#allowableValues}}{{#enumVars}}
- {{#jvm}}
+ {{^multiplatform}}
{{#moshi}}
@Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
{{/moshi}}
{{#gson}}
@SerializedName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
{{/gson}}
- {{/jvm}}
+ {{/multiplatform}}
{{#isListContainer}}
{{#isList}}
{{&name}}(listOf({{{value}}})){{^-last}},{{/-last}}{{#-last}};{{/-last}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/api.mustache
new file mode 100644
index 00000000000..b9e20312aae
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/api.mustache
@@ -0,0 +1,38 @@
+package {{apiPackage}}
+
+import {{packageName}}.infrastructure.CollectionFormats.*
+import retrofit2.http.*
+import retrofit2.Call
+import okhttp3.RequestBody
+import okhttp3.ResponseBody
+import okhttp3.MultipartBody
+
+{{#imports}}import {{import}}
+{{/imports}}
+
+{{#operations}}
+interface {{classname}} {
+ {{#operation}}
+ {{#isDeprecated}}
+ @Deprecated("This api was deprecated")
+ {{/isDeprecated}}
+ {{#formParams}}
+ {{#-first}}
+ {{#isMultipart}}@Multipart{{/isMultipart}}{{^isMultipart}}@FormUrlEncoded{{/isMultipart}}
+ {{/-first}}
+ {{/formParams}}
+ {{^formParams}}
+ {{#prioritizedContentTypes}}
+ {{#-first}}
+ @Headers({
+ "Content-Type:{{{mediaType}}}"
+ })
+ {{/-first}}
+ {{/prioritizedContentTypes}}
+ {{/formParams}}
+ @{{httpMethod}}("{{{path}}}")
+ fun {{operationId}}({{^allParams}}){{/allParams}}{{#allParams}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}}){{/hasMore}}{{/allParams}}: Call<{{#isResponseFile}}ResponseBody{{/isResponseFile}}{{^isResponseFile}}{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}}{{/isResponseFile}}>
+
+ {{/operation}}
+}
+{{/operations}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/bodyParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/bodyParams.mustache
new file mode 100644
index 00000000000..079fbb1169b
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/bodyParams.mustache
@@ -0,0 +1 @@
+{{#isBodyParam}}@Body {{paramName}}: {{{dataType}}}{{/isBodyParam}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/formParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/formParams.mustache
new file mode 100644
index 00000000000..5a7f687061d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/formParams.mustache
@@ -0,0 +1 @@
+{{#isFormParam}}{{^isFile}}{{#isMultipart}}@Part{{/isMultipart}}{{^isMultipart}}@Field{{/isMultipart}}("{{baseName}}") {{paramName}}: {{{dataType}}}{{/isFile}}{{#isFile}}{{#isMultipart}}@Part{{/isMultipart}}{{^isMultipart}}@Field("{{baseName}}"){{/isMultipart}} {{paramName}}: MultipartBody.Part {{/isFile}}{{/isFormParam}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/headerParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/headerParams.mustache
new file mode 100644
index 00000000000..2b26c446678
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/headerParams.mustache
@@ -0,0 +1 @@
+{{#isHeaderParam}}@Header("{{baseName}}") {{paramName}}: {{{dataType}}}{{/isHeaderParam}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/ApiClient.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/ApiClient.kt.mustache
new file mode 100644
index 00000000000..eab46f77ad4
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/ApiClient.kt.mustache
@@ -0,0 +1,43 @@
+package {{packageName}}.infrastructure
+
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import retrofit2.converter.scalars.ScalarsConverterFactory
+{{#gson}}
+import retrofit2.converter.gson.GsonConverterFactory
+{{/gson}}
+{{#moshi}}
+import retrofit2.converter.moshi.MoshiConverterFactory
+{{/moshi}}
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class ApiClient(
+ private var baseUrl: String = "{{{basePath}}}",
+ private var okHttpClient: OkHttpClient
+) {
+ init {
+ normalizeBaseUrl()
+ }
+
+ val retrofitBuilder: Retrofit.Builder by lazy {
+
+ Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .addConverterFactory(ScalarsConverterFactory.create())
+ {{#gson}}
+ .addConverterFactory(GsonConverterFactory.create(Serializer.gson))
+ {{/gson}}
+ {{#moshi}}
+ .addConverterFactory(MoshiConverterFactory.create(Serializer.moshi))
+ {{/moshi}}
+ }
+
+ fun createService(serviceClass: Class): S {
+ return retrofitBuilder.client(okHttpClient).build().create(serviceClass)
+ }
+
+ private fun normalizeBaseUrl() {
+ if (!baseUrl.endsWith("/")) {
+ baseUrl += "/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/ByteArrayAdapter.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/ByteArrayAdapter.kt.mustache
new file mode 100644
index 00000000000..9f56848226c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/ByteArrayAdapter.kt.mustache
@@ -0,0 +1,50 @@
+package {{packageName}}.infrastructure
+
+{{#moshi}}
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+{{/moshi}}
+{{#gson}}
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonWriter
+import com.google.gson.stream.JsonToken.NULL
+import java.io.IOException
+{{/gson}}
+
+{{#moshi}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class ByteArrayAdapter {
+ @ToJson
+ fun toJson(data: ByteArray): String = String(data)
+
+ @FromJson
+ fun fromJson(data: String): ByteArray = data.toByteArray()
+}
+{{/moshi}}
+{{#gson}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class ByteArrayAdapter : TypeAdapter() {
+ @Throws(IOException::class)
+ override fun write(out: JsonWriter?, value: ByteArray?) {
+ if (value == null) {
+ out?.nullValue()
+ } else {
+ out?.value(String(value))
+ }
+ }
+
+ @Throws(IOException::class)
+ override fun read(out: JsonReader?): ByteArray? {
+ out ?: return null
+
+ when (out.peek()) {
+ NULL -> {
+ out.nextNull()
+ return null
+ }
+ else -> {
+ return out.nextString().toByteArray()
+ }
+ }
+ }
+}
+{{/gson}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/CollectionFormats.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/CollectionFormats.kt.mustache
new file mode 100644
index 00000000000..659f2df4851
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/CollectionFormats.kt.mustache
@@ -0,0 +1,56 @@
+package {{packageName}}.infrastructure
+
+class CollectionFormats {
+
+ open class CSVParams {
+
+ var params: List
+
+ constructor(params: List) {
+ this.params = params
+ }
+
+ constructor(vararg params: String) {
+ this.params = listOf(*params)
+ }
+
+ override fun toString(): String {
+ return params.joinToString(",")
+ }
+ }
+
+ open class SSVParams : CSVParams {
+
+ constructor(params: List) : super(params)
+
+ constructor(vararg params: String) : super(*params)
+
+ override fun toString(): String {
+ return params.joinToString(" ")
+ }
+ }
+
+ class TSVParams : CSVParams {
+
+ constructor(params: List) : super(params)
+
+ constructor(vararg params: String) : super(*params)
+
+ override fun toString(): String {
+ return params.joinToString("\t")
+ }
+ }
+
+ class PIPESParams : CSVParams {
+
+ constructor(params: List) : super(params)
+
+ constructor(vararg params: String) : super(*params)
+
+ override fun toString(): String {
+ return params.joinToString("|")
+ }
+ }
+
+ class SPACEParams : SSVParams()
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/DateAdapter.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/DateAdapter.kt.mustache
new file mode 100644
index 00000000000..e24c32c87aa
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/DateAdapter.kt.mustache
@@ -0,0 +1,37 @@
+package {{packageName}}.infrastructure
+
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonWriter
+import com.google.gson.stream.JsonToken.NULL
+import java.io.IOException
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class DateAdapter(val formatter: DateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault())) : TypeAdapter() {
+ @Throws(IOException::class)
+ override fun write(out: JsonWriter?, value: Date?) {
+ if (value == null) {
+ out?.nullValue()
+ } else {
+ out?.value(formatter.format(value))
+ }
+ }
+
+ @Throws(IOException::class)
+ override fun read(out: JsonReader?): Date? {
+ out ?: return null
+
+ when (out.peek()) {
+ NULL -> {
+ out.nextNull()
+ return null
+ }
+ else -> {
+ return formatter.parse(out.nextString())
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/LocalDateAdapter.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/LocalDateAdapter.kt.mustache
new file mode 100644
index 00000000000..152266a5964
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/LocalDateAdapter.kt.mustache
@@ -0,0 +1,63 @@
+package {{packageName}}.infrastructure
+
+{{#moshi}}
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+{{/moshi}}
+{{#gson}}
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonWriter
+import com.google.gson.stream.JsonToken.NULL
+import java.io.IOException
+{{/gson}}
+{{^threetenbp}}
+import java.time.LocalDate
+import java.time.format.DateTimeFormatter
+{{/threetenbp}}
+{{#threetenbp}}
+import org.threeten.bp.LocalDate
+import org.threeten.bp.format.DateTimeFormatter
+{{/threetenbp}}
+
+{{#moshi}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class LocalDateAdapter {
+ @ToJson
+ fun toJson(value: LocalDate): String {
+ return DateTimeFormatter.ISO_LOCAL_DATE.format(value)
+ }
+
+ @FromJson
+ fun fromJson(value: String): LocalDate {
+ return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE)
+ }
+
+}
+{{/moshi}}
+{{#gson}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class LocalDateAdapter(private val formatter: DateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE) : TypeAdapter() {
+ @Throws(IOException::class)
+ override fun write(out: JsonWriter?, value: LocalDate?) {
+ if (value == null) {
+ out?.nullValue()
+ } else {
+ out?.value(formatter.format(value))
+ }
+ }
+
+ @Throws(IOException::class)
+ override fun read(out: JsonReader?): LocalDate? {
+ out ?: return null
+
+ when (out.peek()) {
+ NULL -> {
+ out.nextNull()
+ return null
+ }
+ else -> {
+ return LocalDate.parse(out.nextString(), formatter)
+ }
+ }
+ }
+}
+{{/gson}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/LocalDateTimeAdapter.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/LocalDateTimeAdapter.kt.mustache
new file mode 100644
index 00000000000..0935b0053e5
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/LocalDateTimeAdapter.kt.mustache
@@ -0,0 +1,63 @@
+package {{packageName}}.infrastructure
+
+{{#moshi}}
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+{{/moshi}}
+{{#gson}}
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonWriter
+import com.google.gson.stream.JsonToken.NULL
+import java.io.IOException
+{{/gson}}
+{{^threetenbp}}
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+{{/threetenbp}}
+{{#threetenbp}}
+import org.threeten.bp.LocalDateTime
+import org.threeten.bp.format.DateTimeFormatter
+{{/threetenbp}}
+
+{{#moshi}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class LocalDateTimeAdapter {
+ @ToJson
+ fun toJson(value: LocalDateTime): String {
+ return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value)
+ }
+
+ @FromJson
+ fun fromJson(value: String): LocalDateTime {
+ return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
+ }
+
+}
+{{/moshi}}
+{{#gson}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class LocalDateTimeAdapter(private val formatter: DateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME) : TypeAdapter() {
+ @Throws(IOException::class)
+ override fun write(out: JsonWriter?, value: LocalDateTime?) {
+ if (value == null) {
+ out?.nullValue()
+ } else {
+ out?.value(formatter.format(value))
+ }
+ }
+
+ @Throws(IOException::class)
+ override fun read(out: JsonReader?): LocalDateTime? {
+ out ?: return null
+
+ when (out.peek()) {
+ NULL -> {
+ out.nextNull()
+ return null
+ }
+ else -> {
+ return LocalDateTime.parse(out.nextString(), formatter)
+ }
+ }
+ }
+}
+{{/gson}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/Serializer.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/Serializer.kt.mustache
new file mode 100644
index 00000000000..df4c33c26d2
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/Serializer.kt.mustache
@@ -0,0 +1,45 @@
+package {{packageName}}.infrastructure
+
+{{#moshi}}
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+{{/moshi}}
+{{#gson}}
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+{{^threetenbp}}
+import java.time.LocalDate
+import java.time.LocalDateTime
+{{/threetenbp}}
+{{#threetenbp}}
+import org.threeten.bp.LocalDate
+import org.threeten.bp.LocalDateTime
+{{/threetenbp}}
+import java.util.UUID
+{{/gson}}
+import java.util.Date
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}object Serializer {
+{{#moshi}}
+ @JvmStatic
+ val moshi: Moshi = Moshi.Builder()
+ .add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe())
+ .add(LocalDateTimeAdapter())
+ .add(LocalDateAdapter())
+ .add(UUIDAdapter())
+ .add(ByteArrayAdapter())
+ .add(KotlinJsonAdapterFactory())
+ .build()
+{{/moshi}}
+{{#gson}}
+ @JvmStatic
+ val gson: Gson = GsonBuilder()
+ .registerTypeAdapter(Date::class.java, DateAdapter())
+ .registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter())
+ .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter())
+ .registerTypeAdapter(UUID::class.java, UUIDAdapter())
+ .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter())
+ .create()
+{{/gson}}
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/UUIDAdapter.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/UUIDAdapter.kt.mustache
new file mode 100644
index 00000000000..ad442305b17
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/infrastructure/UUIDAdapter.kt.mustache
@@ -0,0 +1,51 @@
+package {{packageName}}.infrastructure
+
+{{#moshi}}
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+{{/moshi}}
+{{#gson}}
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonWriter
+import com.google.gson.stream.JsonToken.NULL
+import java.io.IOException
+{{/gson}}
+import java.util.UUID
+
+{{#moshi}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class UUIDAdapter {
+ @ToJson
+ fun toJson(uuid: UUID) = uuid.toString()
+
+ @FromJson
+ fun fromJson(s: String) = UUID.fromString(s)
+}
+{{/moshi}}
+{{#gson}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}class UUIDAdapter : TypeAdapter() {
+ @Throws(IOException::class)
+ override fun write(out: JsonWriter?, value: UUID?) {
+ if (value == null) {
+ out?.nullValue()
+ } else {
+ out?.value(value.toString())
+ }
+ }
+
+ @Throws(IOException::class)
+ override fun read(out: JsonReader?): UUID? {
+ out ?: return null
+
+ when (out.peek()) {
+ NULL -> {
+ out.nextNull()
+ return null
+ }
+ else -> {
+ return UUID.fromString(out.nextString())
+ }
+ }
+ }
+}
+{{/gson}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/pathParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/pathParams.mustache
new file mode 100644
index 00000000000..996a45473a9
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/pathParams.mustache
@@ -0,0 +1 @@
+{{#isPathParam}}@Path("{{baseName}}") {{paramName}}: {{{dataType}}}{{/isPathParam}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/queryParams.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/queryParams.mustache
new file mode 100644
index 00000000000..14c40f05e58
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/retrofit2/queryParams.mustache
@@ -0,0 +1 @@
+{{#isQueryParam}}@Query("{{baseName}}") {{paramName}}: {{#collectionFormat}}{{#isCollectionFormatMulti}}{{{dataType}}}{{/isCollectionFormatMulti}}{{^isCollectionFormatMulti}}{{{collectionFormat.toUpperCase}}}Params{{/isCollectionFormatMulti}}{{/collectionFormat}}{{^collectionFormat}}{{{dataType}}}{{/collectionFormat}}{{/isQueryParam}}
\ No newline at end of file
diff --git a/samples/client/petstore/kotlin-retrofit2/.openapi-generator-ignore b/samples/client/petstore/kotlin-retrofit2/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/.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/client/petstore/kotlin-retrofit2/.openapi-generator/VERSION b/samples/client/petstore/kotlin-retrofit2/.openapi-generator/VERSION
new file mode 100644
index 00000000000..58592f031f6
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/.openapi-generator/VERSION
@@ -0,0 +1 @@
+4.2.3-SNAPSHOT
\ No newline at end of file
diff --git a/samples/client/petstore/kotlin-retrofit2/README.md b/samples/client/petstore/kotlin-retrofit2/README.md
new file mode 100644
index 00000000000..000a0a4606e
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/README.md
@@ -0,0 +1,80 @@
+# org.openapitools.client - Kotlin client library for OpenAPI Petstore
+
+## Requires
+
+
+## Build
+
+```
+./gradlew check assemble
+```
+
+This runs all tests and packages the library.
+
+## Features/Implementation Notes
+
+* Supports JSON inputs/outputs, File inputs, 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.client.models.ApiResponse](docs/ApiResponse.md)
+ - [org.openapitools.client.models.Category](docs/Category.md)
+ - [org.openapitools.client.models.Order](docs/Order.md)
+ - [org.openapitools.client.models.Pet](docs/Pet.md)
+ - [org.openapitools.client.models.Tag](docs/Tag.md)
+ - [org.openapitools.client.models.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/client/petstore/kotlin-retrofit2/build.gradle b/samples/client/petstore/kotlin-retrofit2/build.gradle
new file mode 100644
index 00000000000..ced65c34561
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/build.gradle
@@ -0,0 +1,40 @@
+group 'org.openapitools'
+version '1.0.0'
+
+wrapper {
+ gradleVersion = '4.9'
+ distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
+}
+
+buildscript {
+ ext.kotlin_version = '1.3.61'
+ ext.retrofitVersion = '2.6.2'
+
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+apply plugin: 'kotlin'
+
+repositories {
+ mavenCentral()
+}
+
+test {
+ useJUnitPlatform()
+}
+
+dependencies {
+ compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+ compile "com.squareup.moshi:moshi-kotlin:1.9.2"
+ compile "com.squareup.moshi:moshi-adapters:1.9.2"
+ compile "com.squareup.retrofit2:retrofit:$retrofitVersion"
+ compile "com.squareup.retrofit2:converter-moshi:$retrofitVersion"
+ compile "com.squareup.retrofit2:converter-scalars:$retrofitVersion"
+ testCompile "io.kotlintest:kotlintest-runner-junit5:3.1.0"
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/ApiResponse.md b/samples/client/petstore/kotlin-retrofit2/docs/ApiResponse.md
new file mode 100644
index 00000000000..6b4c6bf2779
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/ApiResponse.md
@@ -0,0 +1,12 @@
+
+# ApiResponse
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**code** | **kotlin.Int** | | [optional]
+**type** | **kotlin.String** | | [optional]
+**message** | **kotlin.String** | | [optional]
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/Category.md b/samples/client/petstore/kotlin-retrofit2/docs/Category.md
new file mode 100644
index 00000000000..2c28a670fc7
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/Category.md
@@ -0,0 +1,11 @@
+
+# Category
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**id** | **kotlin.Long** | | [optional]
+**name** | **kotlin.String** | | [optional]
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/Order.md b/samples/client/petstore/kotlin-retrofit2/docs/Order.md
new file mode 100644
index 00000000000..ef31dbf2f4f
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/Order.md
@@ -0,0 +1,22 @@
+
+# Order
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**id** | **kotlin.Long** | | [optional]
+**petId** | **kotlin.Long** | | [optional]
+**quantity** | **kotlin.Int** | | [optional]
+**shipDate** | [**java.time.LocalDateTime**](java.time.LocalDateTime.md) | | [optional]
+**status** | [**inline**](#StatusEnum) | Order Status | [optional]
+**complete** | **kotlin.Boolean** | | [optional]
+
+
+
+## Enum: status
+Name | Value
+---- | -----
+status | placed, approved, delivered
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/Pet.md b/samples/client/petstore/kotlin-retrofit2/docs/Pet.md
new file mode 100644
index 00000000000..ec775600737
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/Pet.md
@@ -0,0 +1,22 @@
+
+# Pet
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**id** | **kotlin.Long** | | [optional]
+**category** | [**Category**](Category.md) | | [optional]
+**name** | **kotlin.String** | |
+**photoUrls** | **kotlin.Array<kotlin.String>** | |
+**tags** | [**kotlin.Array<Tag>**](Tag.md) | | [optional]
+**status** | [**inline**](#StatusEnum) | pet status in the store | [optional]
+
+
+
+## Enum: status
+Name | Value
+---- | -----
+status | available, pending, sold
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/PetApi.md b/samples/client/petstore/kotlin-retrofit2/docs/PetApi.md
new file mode 100644
index 00000000000..ea93e174527
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/PetApi.md
@@ -0,0 +1,405 @@
+# PetApi
+
+All URIs are relative to *http://petstore.swagger.io/v2*
+
+Method | HTTP request | Description
+------------- | ------------- | -------------
+[**addPet**](PetApi.md#addPet) | **POST** /pet | Add a new pet to the store
+[**deletePet**](PetApi.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet
+[**findPetsByStatus**](PetApi.md#findPetsByStatus) | **GET** /pet/findByStatus | Finds Pets by status
+[**findPetsByTags**](PetApi.md#findPetsByTags) | **GET** /pet/findByTags | Finds Pets by tags
+[**getPetById**](PetApi.md#getPetById) | **GET** /pet/{petId} | Find pet by ID
+[**updatePet**](PetApi.md#updatePet) | **PUT** /pet | Update an existing pet
+[**updatePetWithForm**](PetApi.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data
+[**uploadFile**](PetApi.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image
+
+
+
+# **addPet**
+> addPet(body)
+
+Add a new pet to the store
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val body : Pet = // Pet | Pet object that needs to be added to the store
+try {
+ apiInstance.addPet(body)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#addPet")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#addPet")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**Pet**](Pet.md)| Pet object that needs to be added to the store |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: application/json, application/xml
+ - **Accept**: Not defined
+
+
+# **deletePet**
+> deletePet(petId, apiKey)
+
+Deletes a pet
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val petId : kotlin.Long = 789 // kotlin.Long | Pet id to delete
+val apiKey : kotlin.String = apiKey_example // kotlin.String |
+try {
+ apiInstance.deletePet(petId, apiKey)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#deletePet")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#deletePet")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **petId** | **kotlin.Long**| Pet id to delete |
+ **apiKey** | **kotlin.String**| | [optional]
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **findPetsByStatus**
+> kotlin.Array<Pet> findPetsByStatus(status)
+
+Finds Pets by status
+
+Multiple status values can be provided with comma separated strings
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val status : kotlin.Array = // kotlin.Array | Status values that need to be considered for filter
+try {
+ val result : kotlin.Array = apiInstance.findPetsByStatus(status)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#findPetsByStatus")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#findPetsByStatus")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **status** | [**kotlin.Array<kotlin.String>**](kotlin.String.md)| Status values that need to be considered for filter | [enum: available, pending, sold]
+
+### Return type
+
+[**kotlin.Array<Pet>**](Pet.md)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
+
+# **findPetsByTags**
+> kotlin.Array<Pet> findPetsByTags(tags)
+
+Finds Pets by tags
+
+Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val tags : kotlin.Array = // kotlin.Array | Tags to filter by
+try {
+ val result : kotlin.Array = apiInstance.findPetsByTags(tags)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#findPetsByTags")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#findPetsByTags")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **tags** | [**kotlin.Array<kotlin.String>**](kotlin.String.md)| Tags to filter by |
+
+### Return type
+
+[**kotlin.Array<Pet>**](Pet.md)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
+
+# **getPetById**
+> Pet getPetById(petId)
+
+Find pet by ID
+
+Returns a single pet
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to return
+try {
+ val result : Pet = apiInstance.getPetById(petId)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#getPetById")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#getPetById")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **petId** | **kotlin.Long**| ID of pet to return |
+
+### Return type
+
+[**Pet**](Pet.md)
+
+### Authorization
+
+
+Configure api_key:
+ ApiClient.apiKey["api_key"] = ""
+ ApiClient.apiKeyPrefix["api_key"] = ""
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
+
+# **updatePet**
+> updatePet(body)
+
+Update an existing pet
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val body : Pet = // Pet | Pet object that needs to be added to the store
+try {
+ apiInstance.updatePet(body)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#updatePet")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#updatePet")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**Pet**](Pet.md)| Pet object that needs to be added to the store |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: application/json, application/xml
+ - **Accept**: Not defined
+
+
+# **updatePetWithForm**
+> updatePetWithForm(petId, name, status)
+
+Updates a pet in the store with form data
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val petId : kotlin.Long = 789 // kotlin.Long | ID of pet that needs to be updated
+val name : kotlin.String = name_example // kotlin.String | Updated name of the pet
+val status : kotlin.String = status_example // kotlin.String | Updated status of the pet
+try {
+ apiInstance.updatePetWithForm(petId, name, status)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#updatePetWithForm")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#updatePetWithForm")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **petId** | **kotlin.Long**| ID of pet that needs to be updated |
+ **name** | **kotlin.String**| Updated name of the pet | [optional]
+ **status** | **kotlin.String**| Updated status of the pet | [optional]
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: application/x-www-form-urlencoded
+ - **Accept**: Not defined
+
+
+# **uploadFile**
+> ApiResponse uploadFile(petId, additionalMetadata, file)
+
+uploads an image
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = PetApi()
+val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update
+val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server
+val file : java.io.File = BINARY_DATA_HERE // java.io.File | file to upload
+try {
+ val result : ApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling PetApi#uploadFile")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling PetApi#uploadFile")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **petId** | **kotlin.Long**| ID of pet to update |
+ **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional]
+ **file** | **java.io.File**| file to upload | [optional]
+
+### Return type
+
+[**ApiResponse**](ApiResponse.md)
+
+### Authorization
+
+
+Configure petstore_auth:
+ ApiClient.accessToken = ""
+
+### HTTP request headers
+
+ - **Content-Type**: multipart/form-data
+ - **Accept**: application/json
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/StoreApi.md b/samples/client/petstore/kotlin-retrofit2/docs/StoreApi.md
new file mode 100644
index 00000000000..f4986041af8
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/StoreApi.md
@@ -0,0 +1,196 @@
+# StoreApi
+
+All URIs are relative to *http://petstore.swagger.io/v2*
+
+Method | HTTP request | Description
+------------- | ------------- | -------------
+[**deleteOrder**](StoreApi.md#deleteOrder) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
+[**getInventory**](StoreApi.md#getInventory) | **GET** /store/inventory | Returns pet inventories by status
+[**getOrderById**](StoreApi.md#getOrderById) | **GET** /store/order/{orderId} | Find purchase order by ID
+[**placeOrder**](StoreApi.md#placeOrder) | **POST** /store/order | Place an order for a pet
+
+
+
+# **deleteOrder**
+> deleteOrder(orderId)
+
+Delete purchase order by ID
+
+For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = StoreApi()
+val orderId : kotlin.String = orderId_example // kotlin.String | ID of the order that needs to be deleted
+try {
+ apiInstance.deleteOrder(orderId)
+} catch (e: ClientException) {
+ println("4xx response calling StoreApi#deleteOrder")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling StoreApi#deleteOrder")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **orderId** | **kotlin.String**| ID of the order that needs to be deleted |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **getInventory**
+> kotlin.collections.Map<kotlin.String, kotlin.Int> getInventory()
+
+Returns pet inventories by status
+
+Returns a map of status codes to quantities
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = StoreApi()
+try {
+ val result : kotlin.collections.Map = apiInstance.getInventory()
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling StoreApi#getInventory")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling StoreApi#getInventory")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+This endpoint does not need any parameter.
+
+### Return type
+
+**kotlin.collections.Map<kotlin.String, kotlin.Int>**
+
+### Authorization
+
+
+Configure api_key:
+ ApiClient.apiKey["api_key"] = ""
+ ApiClient.apiKeyPrefix["api_key"] = ""
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/json
+
+
+# **getOrderById**
+> Order getOrderById(orderId)
+
+Find purchase order by ID
+
+For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = StoreApi()
+val orderId : kotlin.Long = 789 // kotlin.Long | ID of pet that needs to be fetched
+try {
+ val result : Order = apiInstance.getOrderById(orderId)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling StoreApi#getOrderById")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling StoreApi#getOrderById")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **orderId** | **kotlin.Long**| ID of pet that needs to be fetched |
+
+### Return type
+
+[**Order**](Order.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
+
+# **placeOrder**
+> Order placeOrder(body)
+
+Place an order for a pet
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = StoreApi()
+val body : Order = // Order | order placed for purchasing the pet
+try {
+ val result : Order = apiInstance.placeOrder(body)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling StoreApi#placeOrder")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling StoreApi#placeOrder")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**Order**](Order.md)| order placed for purchasing the pet |
+
+### Return type
+
+[**Order**](Order.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/Tag.md b/samples/client/petstore/kotlin-retrofit2/docs/Tag.md
new file mode 100644
index 00000000000..60ce1bcdbad
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/Tag.md
@@ -0,0 +1,11 @@
+
+# Tag
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**id** | **kotlin.Long** | | [optional]
+**name** | **kotlin.String** | | [optional]
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/User.md b/samples/client/petstore/kotlin-retrofit2/docs/User.md
new file mode 100644
index 00000000000..e801729b5ed
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/User.md
@@ -0,0 +1,17 @@
+
+# User
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**id** | **kotlin.Long** | | [optional]
+**username** | **kotlin.String** | | [optional]
+**firstName** | **kotlin.String** | | [optional]
+**lastName** | **kotlin.String** | | [optional]
+**email** | **kotlin.String** | | [optional]
+**password** | **kotlin.String** | | [optional]
+**phone** | **kotlin.String** | | [optional]
+**userStatus** | **kotlin.Int** | User Status | [optional]
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/docs/UserApi.md b/samples/client/petstore/kotlin-retrofit2/docs/UserApi.md
new file mode 100644
index 00000000000..0f55f06bc62
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/docs/UserApi.md
@@ -0,0 +1,376 @@
+# UserApi
+
+All URIs are relative to *http://petstore.swagger.io/v2*
+
+Method | HTTP request | Description
+------------- | ------------- | -------------
+[**createUser**](UserApi.md#createUser) | **POST** /user | Create user
+[**createUsersWithArrayInput**](UserApi.md#createUsersWithArrayInput) | **POST** /user/createWithArray | Creates list of users with given input array
+[**createUsersWithListInput**](UserApi.md#createUsersWithListInput) | **POST** /user/createWithList | Creates list of users with given input array
+[**deleteUser**](UserApi.md#deleteUser) | **DELETE** /user/{username} | Delete user
+[**getUserByName**](UserApi.md#getUserByName) | **GET** /user/{username} | Get user by user name
+[**loginUser**](UserApi.md#loginUser) | **GET** /user/login | Logs user into the system
+[**logoutUser**](UserApi.md#logoutUser) | **GET** /user/logout | Logs out current logged in user session
+[**updateUser**](UserApi.md#updateUser) | **PUT** /user/{username} | Updated user
+
+
+
+# **createUser**
+> createUser(body)
+
+Create user
+
+This can only be done by the logged in user.
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val body : User = // User | Created user object
+try {
+ apiInstance.createUser(body)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#createUser")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#createUser")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**User**](User.md)| Created user object |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **createUsersWithArrayInput**
+> createUsersWithArrayInput(body)
+
+Creates list of users with given input array
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val body : kotlin.Array = // kotlin.Array | List of user object
+try {
+ apiInstance.createUsersWithArrayInput(body)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#createUsersWithArrayInput")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#createUsersWithArrayInput")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**kotlin.Array<User>**](User.md)| List of user object |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **createUsersWithListInput**
+> createUsersWithListInput(body)
+
+Creates list of users with given input array
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val body : kotlin.Array = // kotlin.Array | List of user object
+try {
+ apiInstance.createUsersWithListInput(body)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#createUsersWithListInput")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#createUsersWithListInput")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**kotlin.Array<User>**](User.md)| List of user object |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **deleteUser**
+> deleteUser(username)
+
+Delete user
+
+This can only be done by the logged in user.
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val username : kotlin.String = username_example // kotlin.String | The name that needs to be deleted
+try {
+ apiInstance.deleteUser(username)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#deleteUser")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#deleteUser")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **username** | **kotlin.String**| The name that needs to be deleted |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **getUserByName**
+> User getUserByName(username)
+
+Get user by user name
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val username : kotlin.String = username_example // kotlin.String | The name that needs to be fetched. Use user1 for testing.
+try {
+ val result : User = apiInstance.getUserByName(username)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#getUserByName")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#getUserByName")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **username** | **kotlin.String**| The name that needs to be fetched. Use user1 for testing. |
+
+### Return type
+
+[**User**](User.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
+
+# **loginUser**
+> kotlin.String loginUser(username, password)
+
+Logs user into the system
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val username : kotlin.String = username_example // kotlin.String | The user name for login
+val password : kotlin.String = password_example // kotlin.String | The password for login in clear text
+try {
+ val result : kotlin.String = apiInstance.loginUser(username, password)
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#loginUser")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#loginUser")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **username** | **kotlin.String**| The user name for login |
+ **password** | **kotlin.String**| The password for login in clear text |
+
+### Return type
+
+**kotlin.String**
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/xml, application/json
+
+
+# **logoutUser**
+> logoutUser()
+
+Logs out current logged in user session
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+try {
+ apiInstance.logoutUser()
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#logoutUser")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#logoutUser")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+This endpoint does not need any parameter.
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
+
+# **updateUser**
+> updateUser(username, body)
+
+Updated user
+
+This can only be done by the logged in user.
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = UserApi()
+val username : kotlin.String = username_example // kotlin.String | name that need to be deleted
+val body : User = // User | Updated user object
+try {
+ apiInstance.updateUser(username, body)
+} catch (e: ClientException) {
+ println("4xx response calling UserApi#updateUser")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling UserApi#updateUser")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **username** | **kotlin.String**| name that need to be deleted |
+ **body** | [**User**](User.md)| Updated user object |
+
+### Return type
+
+null (empty response body)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: Not defined
+
diff --git a/samples/client/petstore/kotlin-retrofit2/settings.gradle b/samples/client/petstore/kotlin-retrofit2/settings.gradle
new file mode 100644
index 00000000000..24c556e079c
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/settings.gradle
@@ -0,0 +1,2 @@
+
+rootProject.name = 'kotlin-petstore-retrofit2'
\ No newline at end of file
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/PetApi.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/PetApi.kt
new file mode 100644
index 00000000000..75f3323445c
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/PetApi.kt
@@ -0,0 +1,41 @@
+package org.openapitools.client.apis
+
+import org.openapitools.client.infrastructure.CollectionFormats.*
+import retrofit2.http.*
+import retrofit2.Call
+import okhttp3.RequestBody
+import okhttp3.ResponseBody
+import okhttp3.MultipartBody
+
+import org.openapitools.client.models.ApiResponse
+import org.openapitools.client.models.Pet
+
+interface PetApi {
+ @POST("/pet")
+ fun addPet(@Body body: Pet): Call
+
+ @DELETE("/pet/{petId}")
+ fun deletePet(@Path("petId") petId: kotlin.Long, @Header("api_key") apiKey: kotlin.String): Call
+
+ @GET("/pet/findByStatus")
+ fun findPetsByStatus(@Query("status") status: CSVParams): Call>
+
+ @Deprecated("This api was deprecated")
+ @GET("/pet/findByTags")
+ fun findPetsByTags(@Query("tags") tags: CSVParams): Call>
+
+ @GET("/pet/{petId}")
+ fun getPetById(@Path("petId") petId: kotlin.Long): Call
+
+ @PUT("/pet")
+ fun updatePet(@Body body: Pet): Call
+
+ @FormUrlEncoded
+ @POST("/pet/{petId}")
+ fun updatePetWithForm(@Path("petId") petId: kotlin.Long, @Field("name") name: kotlin.String, @Field("status") status: kotlin.String): Call
+
+ @Multipart
+ @POST("/pet/{petId}/uploadImage")
+ fun uploadFile(@Path("petId") petId: kotlin.Long, @Part("additionalMetadata") additionalMetadata: kotlin.String, @Part file: MultipartBody.Part ): Call
+
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt
new file mode 100644
index 00000000000..cb0d5b8fa1b
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/StoreApi.kt
@@ -0,0 +1,25 @@
+package org.openapitools.client.apis
+
+import org.openapitools.client.infrastructure.CollectionFormats.*
+import retrofit2.http.*
+import retrofit2.Call
+import okhttp3.RequestBody
+import okhttp3.ResponseBody
+import okhttp3.MultipartBody
+
+import org.openapitools.client.models.Order
+
+interface StoreApi {
+ @DELETE("/store/order/{orderId}")
+ fun deleteOrder(@Path("orderId") orderId: kotlin.String): Call
+
+ @GET("/store/inventory")
+ fun getInventory(): Call>
+
+ @GET("/store/order/{orderId}")
+ fun getOrderById(@Path("orderId") orderId: kotlin.Long): Call
+
+ @POST("/store/order")
+ fun placeOrder(@Body body: Order): Call
+
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/UserApi.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/UserApi.kt
new file mode 100644
index 00000000000..84a6cd43e5e
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/apis/UserApi.kt
@@ -0,0 +1,37 @@
+package org.openapitools.client.apis
+
+import org.openapitools.client.infrastructure.CollectionFormats.*
+import retrofit2.http.*
+import retrofit2.Call
+import okhttp3.RequestBody
+import okhttp3.ResponseBody
+import okhttp3.MultipartBody
+
+import org.openapitools.client.models.User
+
+interface UserApi {
+ @POST("/user")
+ fun createUser(@Body body: User): Call
+
+ @POST("/user/createWithArray")
+ fun createUsersWithArrayInput(@Body body: kotlin.Array): Call
+
+ @POST("/user/createWithList")
+ fun createUsersWithListInput(@Body body: kotlin.Array): Call
+
+ @DELETE("/user/{username}")
+ fun deleteUser(@Path("username") username: kotlin.String): Call
+
+ @GET("/user/{username}")
+ fun getUserByName(@Path("username") username: kotlin.String): Call
+
+ @GET("/user/login")
+ fun loginUser(@Query("username") username: kotlin.String, @Query("password") password: kotlin.String): Call
+
+ @GET("/user/logout")
+ fun logoutUser(): Call
+
+ @PUT("/user/{username}")
+ fun updateUser(@Path("username") username: kotlin.String, @Body body: User): Call
+
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
new file mode 100644
index 00000000000..b539fda7438
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
@@ -0,0 +1,33 @@
+package org.openapitools.client.infrastructure
+
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import retrofit2.converter.moshi.MoshiConverterFactory
+
+class ApiClient(
+ private var baseUrl: String = "http://petstore.swagger.io/v2",
+ private var okHttpClient: OkHttpClient
+) {
+ init {
+ normalizeBaseUrl()
+ }
+
+ val retrofitBuilder: Retrofit.Builder by lazy {
+
+ Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .addConverterFactory(MoshiConverterFactory.create(Serializer.moshi))
+ }
+
+ fun createService(serviceClass: Class): S {
+ return retrofitBuilder.client(okHttpClient).build().create(serviceClass)
+ }
+
+ private fun normalizeBaseUrl() {
+ if (!baseUrl.endsWith("/")) {
+ baseUrl += "/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt
new file mode 100644
index 00000000000..ff5e2a81ee8
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt
@@ -0,0 +1,12 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+
+class ByteArrayAdapter {
+ @ToJson
+ fun toJson(data: ByteArray): String = String(data)
+
+ @FromJson
+ fun fromJson(data: String): ByteArray = data.toByteArray()
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/CollectionFormats.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/CollectionFormats.kt
new file mode 100644
index 00000000000..001e99325d2
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/CollectionFormats.kt
@@ -0,0 +1,56 @@
+package org.openapitools.client.infrastructure
+
+class CollectionFormats {
+
+ open class CSVParams {
+
+ var params: List
+
+ constructor(params: List) {
+ this.params = params
+ }
+
+ constructor(vararg params: String) {
+ this.params = listOf(*params)
+ }
+
+ override fun toString(): String {
+ return params.joinToString(",")
+ }
+ }
+
+ open class SSVParams : CSVParams {
+
+ constructor(params: List) : super(params)
+
+ constructor(vararg params: String) : super(*params)
+
+ override fun toString(): String {
+ return params.joinToString(" ")
+ }
+ }
+
+ class TSVParams : CSVParams {
+
+ constructor(params: List) : super(params)
+
+ constructor(vararg params: String) : super(*params)
+
+ override fun toString(): String {
+ return params.joinToString("\t")
+ }
+ }
+
+ class PIPESParams : CSVParams {
+
+ constructor(params: List) : super(params)
+
+ constructor(vararg params: String) : super(*params)
+
+ override fun toString(): String {
+ return params.joinToString("|")
+ }
+ }
+
+ class SPACEParams : SSVParams()
+}
\ No newline at end of file
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt
new file mode 100644
index 00000000000..b2e1654479a
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.time.LocalDate
+import java.time.format.DateTimeFormatter
+
+class LocalDateAdapter {
+ @ToJson
+ fun toJson(value: LocalDate): String {
+ return DateTimeFormatter.ISO_LOCAL_DATE.format(value)
+ }
+
+ @FromJson
+ fun fromJson(value: String): LocalDate {
+ return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE)
+ }
+
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt
new file mode 100644
index 00000000000..e082db94811
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+
+class LocalDateTimeAdapter {
+ @ToJson
+ fun toJson(value: LocalDateTime): String {
+ return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value)
+ }
+
+ @FromJson
+ fun fromJson(value: String): LocalDateTime {
+ return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
+ }
+
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
new file mode 100644
index 00000000000..7c5a353e0f7
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
@@ -0,0 +1,18 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+import java.util.Date
+
+object Serializer {
+ @JvmStatic
+ val moshi: Moshi = Moshi.Builder()
+ .add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe())
+ .add(LocalDateTimeAdapter())
+ .add(LocalDateAdapter())
+ .add(UUIDAdapter())
+ .add(ByteArrayAdapter())
+ .add(KotlinJsonAdapterFactory())
+ .build()
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt
new file mode 100644
index 00000000000..a4a44cc18b7
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt
@@ -0,0 +1,13 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.util.UUID
+
+class UUIDAdapter {
+ @ToJson
+ fun toJson(uuid: UUID) = uuid.toString()
+
+ @FromJson
+ fun fromJson(s: String) = UUID.fromString(s)
+}
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/ApiResponse.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/ApiResponse.kt
new file mode 100644
index 00000000000..47766821f18
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/ApiResponse.kt
@@ -0,0 +1,33 @@
+/**
+* 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.client.models
+
+
+import com.squareup.moshi.Json
+/**
+ * Describes the result of uploading an image resource
+ * @param code
+ * @param type
+ * @param message
+ */
+
+data class ApiResponse (
+ @Json(name = "code")
+ val code: kotlin.Int? = null,
+ @Json(name = "type")
+ val type: kotlin.String? = null,
+ @Json(name = "message")
+ val message: kotlin.String? = null
+)
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Category.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Category.kt
new file mode 100644
index 00000000000..edb16cc1270
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Category.kt
@@ -0,0 +1,30 @@
+/**
+* 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.client.models
+
+
+import com.squareup.moshi.Json
+/**
+ * A category for a pet
+ * @param id
+ * @param name
+ */
+
+data class Category (
+ @Json(name = "id")
+ val id: kotlin.Long? = null,
+ @Json(name = "name")
+ val name: kotlin.String? = null
+)
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Order.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Order.kt
new file mode 100644
index 00000000000..bcdb149159b
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/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.client.models
+
+
+import com.squareup.moshi.Json
+/**
+ * An order for a pets from the pet store
+ * @param id
+ * @param petId
+ * @param quantity
+ * @param shipDate
+ * @param status Order Status
+ * @param complete
+ */
+
+data class Order (
+ @Json(name = "id")
+ val id: kotlin.Long? = null,
+ @Json(name = "petId")
+ val petId: kotlin.Long? = null,
+ @Json(name = "quantity")
+ val quantity: kotlin.Int? = null,
+ @Json(name = "shipDate")
+ val shipDate: java.time.LocalDateTime? = null,
+ /* Order Status */
+ @Json(name = "status")
+ val status: Order.Status? = null,
+ @Json(name = "complete")
+ val complete: kotlin.Boolean? = null
+)
+
+
+{
+ /**
+ * Order Status
+ * Values: placed,approved,delivered
+ */
+
+ enum class Status(val value: kotlin.String){
+ @Json(name = "placed") placed("placed"),
+ @Json(name = "approved") approved("approved"),
+ @Json(name = "delivered") delivered("delivered");
+ }
+}
+
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Pet.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Pet.kt
new file mode 100644
index 00000000000..f6f7371601f
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Pet.kt
@@ -0,0 +1,57 @@
+/**
+* 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.client.models
+
+import org.openapitools.client.models.Category
+import org.openapitools.client.models.Tag
+
+import com.squareup.moshi.Json
+/**
+ * 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
+ */
+
+data class Pet (
+ @Json(name = "name")
+ val name: kotlin.String,
+ @Json(name = "photoUrls")
+ val photoUrls: kotlin.Array,
+ @Json(name = "id")
+ val id: kotlin.Long? = null,
+ @Json(name = "category")
+ val category: Category? = null,
+ @Json(name = "tags")
+ val tags: kotlin.Array? = null,
+ /* pet status in the store */
+ @Json(name = "status")
+ val status: Pet.Status? = null
+)
+
+
+{
+ /**
+ * pet status in the store
+ * Values: available,pending,sold
+ */
+
+ enum class Status(val value: kotlin.String){
+ @Json(name = "available") available("available"),
+ @Json(name = "pending") pending("pending"),
+ @Json(name = "sold") sold("sold");
+ }
+}
+
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Tag.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Tag.kt
new file mode 100644
index 00000000000..05dc7c9afef
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/Tag.kt
@@ -0,0 +1,30 @@
+/**
+* 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.client.models
+
+
+import com.squareup.moshi.Json
+/**
+ * A tag for a pet
+ * @param id
+ * @param name
+ */
+
+data class Tag (
+ @Json(name = "id")
+ val id: kotlin.Long? = null,
+ @Json(name = "name")
+ val name: kotlin.String? = null
+)
+
+
+
diff --git a/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/User.kt b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/User.kt
new file mode 100644
index 00000000000..537b01d3c27
--- /dev/null
+++ b/samples/client/petstore/kotlin-retrofit2/src/main/kotlin/org/openapitools/client/models/User.kt
@@ -0,0 +1,49 @@
+/**
+* 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.client.models
+
+
+import com.squareup.moshi.Json
+/**
+ * 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
+ */
+
+data class User (
+ @Json(name = "id")
+ val id: kotlin.Long? = null,
+ @Json(name = "username")
+ val username: kotlin.String? = null,
+ @Json(name = "firstName")
+ val firstName: kotlin.String? = null,
+ @Json(name = "lastName")
+ val lastName: kotlin.String? = null,
+ @Json(name = "email")
+ val email: kotlin.String? = null,
+ @Json(name = "password")
+ val password: kotlin.String? = null,
+ @Json(name = "phone")
+ val phone: kotlin.String? = null,
+ /* User Status */
+ @Json(name = "userStatus")
+ val userStatus: kotlin.Int? = null
+)
+
+
+