diff --git a/.gitignore b/.gitignore
index e24cf380cfea..efe3fab179e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -195,14 +195,11 @@ samples/server/petstore/aspnetcore/.vs/
effective.pom
# kotlin
-samples/client/petstore/kotlin/src/main/kotlin/test/
-samples/client/petstore/kotlin-threetenbp/build
-samples/client/petstore/kotlin-string/build
+samples/client/petstore/kotlin*/build
+samples/client/petstore/kotlin*/.gradle
samples/openapi3/client/petstore/kotlin/build
samples/server/petstore/kotlin-server/ktor/build
samples/server/petstore/kotlin-springboot/build
-samples/client/petstore/kotlin-multiplatform/build/
-samples/client/petstore/kotlin-okhttp3/build/
\?
# haskell
diff --git a/docs/generators/kotlin.md b/docs/generators/kotlin.md
index c53f7f7a59df..1960dcae3c88 100644
--- a/docs/generators/kotlin.md
+++ b/docs/generators/kotlin.md
@@ -10,7 +10,7 @@ sidebar_label: kotlin
|artifactVersion|Generated artifact's package version.| |1.0.0|
|collectionType|Option. Collection type to use|
- **array**
- kotlin.Array
- **list**
- kotlin.collections.List
|list|
|dateLibrary|Option. Date library to use|- **threetenbp-localdatetime**
- Threetenbp - Backport of JSR310 (jvm only, for legacy app only)
- **string**
- String
- **java8-localdatetime**
- Java 8 native JSR310 (jvm only, for legacy app only)
- **java8**
- Java 8 native JSR310 (jvm only, preferred for jdk 1.8+)
- **threetenbp**
- Threetenbp - Backport of JSR310 (jvm only, preferred for jdk < 1.8)
|java8|
-|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
+|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|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.
- **jvm-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|
|modelMutable|Create mutable models| |false|
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 1ac723a984e1..f376392238aa 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
@@ -72,6 +72,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
// (mustache does not allow for boolean operators so we need this extra field)
protected boolean doNotUseRxAndCoroutines = true;
+ protected String baseFolder;
protected String authFolder;
public enum DateLibrary {
@@ -150,6 +151,8 @@ public KotlinClientCodegen() {
// cliOptions default redefinition need to be updated
updateOption(CodegenConstants.ARTIFACT_ID, this.artifactId);
updateOption(CodegenConstants.PACKAGE_NAME, this.packageName);
+ // Kotlin convention
+ updateOption(CodegenConstants.ENUM_PROPERTY_NAMING, "PascalCase");
outputFolder = "generated-code" + File.separator + "kotlin-client";
modelTemplateFiles.put("model.mustache", ".kt");
@@ -284,7 +287,7 @@ public void processOpts() {
super.processOpts();
if (MULTIPLATFORM.equals(getLibrary())) {
- sourceFolder = "src/commonMain/kotlin";
+ sourceFolder = "src/common/main";
}
@@ -311,13 +314,13 @@ public void processOpts() {
if (hasConflict) {
LOGGER.warn("You specified RxJava versions 1 and 2 and 3 or Coroutines together, please choose one of them.");
} else if (hasRx) {
- this.setUseRxJava(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA).toString()));
+ this.setUseRxJava(Boolean.parseBoolean(additionalProperties.get(USE_RX_JAVA).toString()));
} else if (hasRx2) {
- this.setUseRxJava2(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA2).toString()));
+ this.setUseRxJava2(Boolean.parseBoolean(additionalProperties.get(USE_RX_JAVA2).toString()));
} else if (hasRx3) {
- this.setUseRxJava3(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA3).toString()));
+ this.setUseRxJava3(Boolean.parseBoolean(additionalProperties.get(USE_RX_JAVA3).toString()));
} else if (hasCoroutines) {
- this.setUseCoroutines(Boolean.valueOf(additionalProperties.get(USE_COROUTINES).toString()));
+ this.setUseCoroutines(Boolean.parseBoolean(additionalProperties.get(USE_COROUTINES).toString()));
}
if (!hasRx && !hasRx2 && !hasRx3 && !hasCoroutines) {
@@ -327,7 +330,8 @@ public void processOpts() {
// infrastructure destination folder
final String infrastructureFolder = (sourceFolder + File.separator + packageName + File.separator + "infrastructure").replace(".", "/");
- authFolder = (sourceFolder + File.separator + packageName + File.separator + "auth").replace(".", "/");
+ authFolder = (sourceFolder + File.separator + packageName + File.separator + "auth").replace(".", File.separator);
+ baseFolder = (sourceFolder + File.separator + packageName).replace(".", File.separator);
// additional properties
if (additionalProperties.containsKey(DATE_LIBRARY)) {
@@ -496,6 +500,7 @@ private void processJVMOkHttpLibrary(final String infrastructureFolder) {
setLibrary(JVM_OKHTTP);
// jvm specific supporting files
+ supportingFiles.add(new SupportingFile("infrastructure/ApiClient.kt.mustache", infrastructureFolder, "ApiClient.kt"));
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"));
@@ -533,11 +538,16 @@ private void processMultiplatformLibrary(final String infrastructureFolder) {
importMapping.put("Base64ByteArray", packageName + ".infrastructure.Base64ByteArray");
importMapping.put("OctetByteArray", packageName + ".infrastructure.OctetByteArray");
+ // bundled client file
+ supportingFiles.add(new SupportingFile("ApiClient.kt.mustache", baseFolder, "ApiClient.kt"));
+
// multiplatform specific supporting files
+ supportingFiles.add(new SupportingFile("infrastructure/ApiClientBase.kt.mustache", infrastructureFolder, "ApiClientBase.kt"));
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"));
+ supportingFiles.add(new SupportingFile("infrastructure/encoding.kt.mustache", infrastructureFolder, "encoding.kt"));
// multiplatform specific auth
supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.kt.mustache", authFolder, "ApiKeyAuth.kt"));
@@ -547,30 +557,35 @@ private void processMultiplatformLibrary(final String infrastructureFolder) {
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"));
+ supportingFiles.add(new SupportingFile("commonTest/Coroutine.kt.mustache", "src/common/test/util", "Coroutine.kt"));
+ supportingFiles.add(new SupportingFile("iosTest/Coroutine.kt.mustache", "src/ios/test/util", "Coroutine.kt"));
+ supportingFiles.add(new SupportingFile("jsTest/Coroutine.kt.mustache", "src/js/test/util", "Coroutine.kt"));
+ supportingFiles.add(new SupportingFile("jvmTest/Coroutine.kt.mustache", "src/jvm/test/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.properties", "", "gradle.properties"));
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() {
+ if (MULTIPLATFORM.equals(getLibrary())) {
+ supportingFiles.add(new SupportingFile("build.gradle.kts.mustache", "", "build.gradle.kts"));
+ supportingFiles.add(new SupportingFile("settings.gradle.kts.mustache", "", "settings.gradle.kts"));
+ } else {
+ supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
+ supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
+ }
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/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/README.mustache
index eebddf4b1961..85e183eed494 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/README.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/README.mustache
@@ -7,7 +7,7 @@
* Gradle 4.9
{{/jvm}}
{{#multiplatform}}
-* Kotlin 1.3.50
+* Kotlin 1.3.72
{{/multiplatform}}
## Build
@@ -36,7 +36,7 @@ This runs all tests and packages the library.
{{#jvm}}* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets.{{/jvm}}
{{#generateApiDocs}}
-
+
## Documentation for API Endpoints
All URIs are relative to *{{{basePath}}}*
@@ -48,7 +48,7 @@ Class | Method | HTTP request | Description
{{/generateApiDocs}}
{{#generateModelDocs}}
-
+
## Documentation for Models
{{#modelPackage}}
@@ -60,7 +60,7 @@ No model defined in this package
{{/modelPackage}}
{{/generateModelDocs}}
-{{! TODO: optional documentation for authorization? }}
+{{! TODO: optional documentation for authorization? }}
## Documentation for Authorization
{{^authMethods}}
@@ -72,7 +72,7 @@ Authentication schemes defined for the API:
{{/last}}
{{/authMethods}}
{{#authMethods}}
-
+
### {{name}}
{{#isApiKey}}- **Type**: API key
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/class_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/class_doc.mustache
index a3405b25c845..b6b482afb78b 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/class_doc.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/class_doc.mustache
@@ -7,7 +7,7 @@ Name | Type | Description | Notes
{{/vars}}
{{#vars}}{{#isEnum}}
-{{!NOTE: see java's resources "pojo_doc.mustache" once enums are fully implemented}}
+{{!NOTE: see java's resources "pojo_doc.mustache" once enums are fully implemented}}
## Enum: {{baseName}}
Name | Value
---- | -----{{#allowableValues}}
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 1b63b0878117..ba3132e00d60 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
@@ -23,14 +23,15 @@ import kotlinx.android.parcel.Parcelize
{{/multiplatform}}
{{#multiplatform}}
import kotlinx.serialization.*
-import kotlinx.serialization.internal.CommonEnumSerializer
{{/multiplatform}}
{{#serializableModel}}
import java.io.Serializable
{{/serializableModel}}
+import kotlin.collections.*
/**
* {{{description}}}
+ *
{{#allVars}}
* @param {{{name}}} {{{description}}}
{{/allVars}}
@@ -42,7 +43,7 @@ import java.io.Serializable
{{#isDeprecated}}
@Deprecated(message = "This schema is deprecated.")
{{/isDeprecated}}
-{{#nonPublicApi}}internal {{/nonPublicApi}}{{#discriminator}}interface{{/discriminator}}{{^discriminator}}data class{{/discriminator}} {{classname}}{{^discriminator}} (
+{{#nonPublicApi}}internal {{/nonPublicApi}}{{#discriminator}}interface{{/discriminator}}{{^discriminator}}data class{{/discriminator}} {{classname}}{{^discriminator}}(
{{#allVars}}
{{#required}}{{>data_class_req_var}}{{/required}}{{^required}}{{>data_class_opt_var}}{{/required}}{{^-last}},{{/-last}}
{{/allVars}}
@@ -60,14 +61,13 @@ import java.io.Serializable
{{#vars}}
{{#isEnum}}
/**
- * {{{description}}}
- * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
- */
- {{#multiplatform}}@Serializable(with = {{nameInCamelCase}}.Serializer::class){{/multiplatform}}
- {{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{{nameInCamelCase}}}(val value: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}kotlin.String{{/isContainer}}){
+ * {{{description}}}
+ *
+ * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
+ */
+ {{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{{nameInCamelCase}}}(val value: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}String{{/isContainer}}){
{{#allowableValues}}
{{#enumVars}}
- {{^multiplatform}}
{{#moshi}}
@Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/moshi}}
@@ -77,16 +77,11 @@ import java.io.Serializable
{{#jackson}}
@JsonProperty(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/jackson}}
- {{/multiplatform}}
{{#multiplatform}}
- {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
+ @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/multiplatform}}
{{/enumVars}}
{{/allowableValues}}
- {{#multiplatform}}
-
- {{#nonPublicApi}}internal {{/nonPublicApi}}object Serializer : CommonEnumSerializer<{{nameInCamelCase}}>("{{nameInCamelCase}}", values(), values().map { it.value.toString() }.toTypedArray())
- {{/multiplatform}}
}
{{/isEnum}}
{{/vars}}
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 cbf85029fcab..1b58be900a66 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,5 +1,7 @@
{{#description}}
- /* {{{description}}} */
+ /**
+ * {{{description}}}
+ */
{{/description}}
{{^multiplatform}}
{{#moshi}}
@@ -12,7 +14,10 @@
@field:JsonProperty("{{{vendorExtensions.x-base-name-literal}}}")
{{/jackson}}
{{/multiplatform}}
+ {{#multiplatform}}
+ @SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}")
+ {{/multiplatform}}
{{#deprecated}}
@Deprecated(message = "This property is deprecated.")
{{/deprecated}}
- {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") {{/multiplatform}}{{#isInherited}}override {{/isInherited}}{{>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
+ {{#isInherited}}override {{/isInherited}}{{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isListContainer}}{{#isList}}List{{/isList}}{{^isList}}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 eb18e85c4ce7..fd9740086a77 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,5 +1,7 @@
{{#description}}
- /* {{{description}}} */
+ /**
+ * {{{description}}}
+ */
{{/description}}
{{^multiplatform}}
{{#moshi}}
@@ -15,4 +17,8 @@
{{#deprecated}}
@Deprecated(message = "This property is deprecated.")
{{/deprecated}}
- {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") @Required {{/multiplatform}}{{#isInherited}}override {{/isInherited}}{{>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
+ {{#multiplatform}}
+ @SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}")
+ @Required
+ {{/multiplatform}}
+ {{#isInherited}}override {{/isInherited}}{{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isListContainer}}{{#isList}}List{{/isList}}{{^isList}}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 8de73d460492..8b9d30eb4593 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
@@ -11,15 +11,15 @@ import com.fasterxml.jackson.annotation.JsonProperty
{{/multiplatform}}
{{#multiplatform}}
import kotlinx.serialization.*
-import kotlinx.serialization.internal.CommonEnumSerializer
{{/multiplatform}}
/**
-* {{{description}}}
-* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
-*/
-{{#multiplatform}}@Serializable(with = {{classname}}.Serializer::class){{/multiplatform}}
-{{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{classname}}(val value: {{{dataType}}}){
+ * {{{description}}}
+ *
+ * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
+ */
+{{#multiplatform}}@Serializable{{/multiplatform}}
+{{#nonPublicApi}}internal {{/nonPublicApi}}enum class {{classname}}(val value: {{{dataType}}}) {
{{#allowableValues}}{{#enumVars}}
{{^multiplatform}}
@@ -33,6 +33,9 @@ import kotlinx.serialization.internal.CommonEnumSerializer
@JsonProperty(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
{{/jackson}}
{{/multiplatform}}
+ {{#multiplatform}}
+ @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
+ {{/multiplatform}}
{{#isListContainer}}
{{#isList}}
{{&name}}(listOf({{{value}}})){{^-last}},{{/-last}}{{#-last}};{{/-last}}
@@ -48,14 +51,10 @@ import kotlinx.serialization.internal.CommonEnumSerializer
{{/enumVars}}{{/allowableValues}}
/**
- This override toString avoids using the enum var name and uses the actual api value instead.
- In cases the var name and value are different, the client would send incorrect enums to the server.
- **/
+ * This override toString avoids using the enum var name and uses the actual api value instead.
+ * In cases the var name and value are different, the client would send incorrect enums to the server.
+ */
override fun toString(): String {
return value{{^isString}}.toString(){{/isString}}
}
-
-{{#multiplatform}}
- {{#nonPublicApi}}internal {{/nonPublicApi}}object Serializer : CommonEnumSerializer<{{classname}}>("{{classname}}", values(), values().map { it.value.toString() }.toTypedArray())
-{{/multiplatform}}
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/gradle.properties b/modules/openapi-generator/src/main/resources/kotlin-client/gradle.properties
new file mode 100644
index 000000000000..29e08e8ca88f
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/gradle.properties
@@ -0,0 +1 @@
+kotlin.code.style=official
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/interface_opt_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/interface_opt_var.mustache
index 3284d7b1db41..3c12573fbff6 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/interface_opt_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/interface_opt_var.mustache
@@ -1,5 +1,7 @@
{{#description}}
- /* {{{description}}} */
+ /**
+ * {{{description}}}
+ */
{{/description}}
{{^multiplatform}}
{{#moshi}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/interface_req_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/interface_req_var.mustache
index ee62fbb2d126..cef7ea0a283f 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/interface_req_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/interface_req_var.mustache
@@ -1,5 +1,7 @@
{{#description}}
- /* {{{description}}} */
+ /**
+ * {{{description}}}
+ */
{{/description}}
{{^multiplatform}}
{{#moshi}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/ApiClient.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/ApiClient.kt.mustache
new file mode 100644
index 000000000000..a2d303780706
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/ApiClient.kt.mustache
@@ -0,0 +1,95 @@
+package {{packageName}}
+
+import io.ktor.client.engine.HttpClientEngine
+import kotlinx.serialization.json.Json
+import {{packageName}}.apis.*
+import {{packageName}}.infrastructure.ApiClientBase
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class ApiClient(
+ baseUrl: String = "{{{basePath}}}",
+ httpClientEngine: HttpClientEngine? = null,
+ json: Json = Json {}
+) {
+ {{! TODO: Remove backticks when conflicts are resolved }}
+ {{#apiInfo}}
+ {{#apis}}
+ val `{{{classVarName}}}` = {{{classFilename}}}(baseUrl, httpClientEngine, json)
+ {{/apis}}
+ {{/apiInfo}}
+
+ val allClients: Set = setOf(
+ {{#apiInfo}}
+ {{#apis}}
+ `{{{classVarName}}}`,
+ {{/apis}}
+ {{/apiInfo}}
+ )
+
+ /**
+ * Set the username for the first HTTP basic authentication for all apis.
+ *
+ * @param username Username
+ */
+ fun setUsername(username: String) {
+ for (client in allClients) {
+ client.setUsername(username)
+ }
+ }
+
+ /**
+ * Set the password for the first HTTP basic authentication for all apis.
+ *
+ * @param password Password
+ */
+ fun setPassword(password: String) {
+ for (client in allClients) {
+ client.setPassword(password)
+ }
+ }
+
+ /**
+ * Set the API key value for the first API key authentication for all apis.
+ *
+ * @param apiKey API key
+ * @param paramName The name of the API key parameter, or null or set the first key.
+ */
+ fun setApiKey(apiKey: String, paramName: String? = null) {
+ for (client in allClients) {
+ client.setApiKey(apiKey, paramName)
+ }
+ }
+
+ /**
+ * Set the API key prefix for the first API key authentication for all apis.
+ *
+ * @param apiKeyPrefix API key prefix
+ * @param paramName The name of the API key parameter, or null or set the first key.
+ */
+ fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) {
+ for (client in allClients) {
+ client.setApiKeyPrefix(apiKeyPrefix, paramName)
+ }
+ }
+
+ /**
+ * Set the access token for the first OAuth2 authentication for all apis.
+ *
+ * @param accessToken Access token
+ */
+ fun setAccessToken(accessToken: String) {
+ for (client in allClients) {
+ client.setAccessToken(accessToken)
+ }
+ }
+
+ /**
+ * Set the access token for the first Bearer authentication for all apis.
+ *
+ * @param bearerToken The bearer token.
+ */
+ fun setBearerToken(bearerToken: String) {
+ for (client in allClients) {
+ client.setBearerToken(bearerToken)
+ }
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache
index d268f23a77d3..45f81b639a2c 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache
@@ -6,29 +6,27 @@ package {{apiPackage}}
import {{packageName}}.infrastructure.*
import io.ktor.client.request.forms.formData
-import kotlinx.serialization.UnstableDefault
import io.ktor.client.engine.HttpClientEngine
-import io.ktor.client.features.json.serializer.KotlinxSerializer
+import io.ktor.client.request.forms.FormPart
+import io.ktor.client.utils.EmptyContent
import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
import io.ktor.http.ParametersBuilder
-import kotlinx.serialization.*
-import kotlinx.serialization.internal.StringDescriptor
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.builtins.ListSerializer
+import kotlinx.serialization.builtins.list
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
{{#operations}}
-{{#nonPublicApi}}internal {{/nonPublicApi}}class {{classname}} @UseExperimental(UnstableDefault::class) constructor(
+{{#nonPublicApi}}internal {{/nonPublicApi}}class {{classname}} constructor(
baseUrl: kotlin.String = "{{{basePath}}}",
httpClientEngine: HttpClientEngine? = null,
- serializer: KotlinxSerializer
-) : ApiClient(baseUrl, httpClientEngine, serializer) {
-
- @UseExperimental(UnstableDefault::class)
- constructor(
- baseUrl: kotlin.String = "{{{basePath}}}",
- httpClientEngine: HttpClientEngine? = null,
- jsonConfiguration: JsonConfiguration = JsonConfiguration.Default
- ) : this(baseUrl, httpClientEngine, KotlinxSerializer(Json(jsonConfiguration)))
-
+ json: Json = Json {},
+) : ApiClientBase(baseUrl, httpClientEngine, json) {
{{#operation}}
/**
* {{summary}}
@@ -39,58 +37,74 @@ import kotlinx.serialization.internal.StringDescriptor
{{#returnType}}
@Suppress("UNCHECKED_CAST")
{{/returnType}}
- suspend fun {{operationId}}({{#allParams}}{{{paramName}}}: {{{dataType}}}{{^required}}?{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}): HttpResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}}> {
-
- val localVariableAuthNames = listOf({{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}})
+ suspend fun {{operationId}}(
+ {{#allParams}}
+ {{{paramName}}}: {{{dataType}}}{{^required}}? = null{{/required}}{{#hasMore}},{{/hasMore}}
+ {{/allParams}}
+ ): HttpResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}}> {
+ {{! TODO: Optimize all the ?.let to only the places where it's needed }}
+ val authNamesOag = listOf({{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}})
- val localVariableBody = {{#hasBodyParam}}{{#bodyParam}}{{#isListContainer}}{{operationIdCamelCase}}Request({{{paramName}}}{{^isList}}.asList(){{/isList}}){{/isListContainer}}{{^isListContainer}}{{#isMapContainer}}{{operationIdCamelCase}}Request({{{paramName}}}){{/isMapContainer}}{{^isMapContainer}}{{{paramName}}}{{/isMapContainer}}{{/isListContainer}}{{/bodyParam}}{{/hasBodyParam}}
+ val bodyOag = {{#hasBodyParam}}{{#bodyParam}}{{#isListContainer}}{{^required}}{{{paramName}}}?.let { {{/required}}{{operationIdCamelCase}}Request({{{paramName}}}{{^isList}}.asList(){{/isList}}){{^required}} }{{/required}}{{/isListContainer}}{{^isListContainer}}{{#isMapContainer}}{{^required}}{{{paramName}}}?.let { {{/required}}{{operationIdCamelCase}}Request({{{paramName}}}){{^required}} }{{/required}}{{/isMapContainer}}{{^isMapContainer}}{{{paramName}}}{{/isMapContainer}}{{/isListContainer}}{{/bodyParam}}{{/hasBodyParam}}
{{^hasBodyParam}}
{{#hasFormParams}}
{{#isMultipart}}
formData {
{{#formParams}}
- {{{paramName}}}?.apply { append("{{{baseName}}}", {{{paramName}}}) }
+ {{^required}}{{{paramName}}}?.let { {{/required}}append(FormPart("{{{baseName}}}", {{{paramName}}})){{^required}} }{{/required}}
{{/formParams}}
}
{{/isMultipart}}
{{^isMultipart}}
ParametersBuilder().also {
{{#formParams}}
- {{{paramName}}}?.apply { it.append("{{{baseName}}}", {{{paramName}}}.toString()) }
+ {{^required}}{{{paramName}}}?.apply { {{/required}}it.append("{{{baseName}}}", {{{paramName}}}.toString()){{^required}} }{{/required}}
{{/formParams}}
}.build()
{{/isMultipart}}
{{/hasFormParams}}
{{^hasFormParams}}
- io.ktor.client.utils.EmptyContent
+ EmptyContent
{{/hasFormParams}}
{{/hasBodyParam}}
- val localVariableQuery = mutableMapOf>()
- {{#queryParams}}
- {{{paramName}}}?.apply { localVariableQuery["{{baseName}}"] = {{#isContainer}}toMultiValue(this, "{{collectionFormat}}"){{/isContainer}}{{^isContainer}}listOf("${{{paramName}}}"){{/isContainer}} }
- {{/queryParams}}
+ val queriesOag = Queries {
+ {{#queryParams}}
+ {{#isContainer}}
+ {{#isMapContainer}}
+ {{^required}}if ({{{paramName}}} != null) {{/required}}addMap({{{paramName}}})
+ {{/isMapContainer}}
+ {{^isMapContainer}}
+ {{^required}}if ({{{paramName}}} != null) {{/required}}addMulti("{{baseName}}", {{{paramName}}}, "{{collectionFormat}}")
+ {{/isMapContainer}}
+ {{/isContainer}}
+ {{^isContainer}}
+ add("{{baseName}}", {{{paramName}}})
+ {{/isContainer}}
+ {{/queryParams}}
+ }
- val localVariableHeaders = mutableMapOf()
- {{#headerParams}}
- {{{paramName}}}?.apply { localVariableHeaders["{{baseName}}"] = {{#isContainer}}this.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}this.toString(){{/isContainer}} }
- {{/headerParams}}
+ val headersOag = mutableMapOf(
+ {{#headerParams}}
+ "{{baseName}}" to {{#isContainer}}{{{paramName}}}?.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}this?.toString(){{/isContainer}}{{#hasMore}},{{/hasMore}}
+ {{/headerParams}}
+ )
- val localVariableConfig = RequestConfig(
+ val configOag = RequestConfig(
RequestMethod.{{httpMethod}},
- "{{path}}"{{#pathParams}}.replace("{" + "{{baseName}}" + "}", "${{{paramName}}}"){{/pathParams}},
- query = localVariableQuery,
- headers = localVariableHeaders
+ "{{path}}"{{#pathParams}}.replace("{" + "{{baseName}}" + "}", {{{paramName}}}.toString()){{/pathParams}},
+ queries = queriesOag,
+ headers = headersOag
)
return {{#hasBodyParam}}jsonRequest{{/hasBodyParam}}{{^hasBodyParam}}{{#hasFormParams}}{{#isMultipart}}multipartFormRequest{{/isMultipart}}{{^isMultipart}}urlEncodedFormRequest{{/isMultipart}}{{/hasFormParams}}{{^hasFormParams}}request{{/hasFormParams}}{{/hasBodyParam}}(
- localVariableConfig,
- localVariableBody,
- localVariableAuthNames
+ configOag,
+ bodyOag,
+ authNamesOag
).{{#isListContainer}}wrap<{{operationIdCamelCase}}Response>().map { value{{^isList}}.toTypedArray(){{/isList}} }{{/isListContainer}}{{^isListContainer}}{{#isMapContainer}}wrap<{{operationIdCamelCase}}Response>().map { value }{{/isMapContainer}}{{^isMapContainer}}wrap(){{/isMapContainer}}{{/isListContainer}}
}
-
{{#hasBodyParam}}
+
{{#bodyParam}}
{{#isListContainer}}{{>serial_wrapper_request_list}}{{/isListContainer}}{{#isMapContainer}}{{>serial_wrapper_request_map}}{{/isMapContainer}}
{{/bodyParam}}
@@ -101,25 +115,6 @@ import kotlinx.serialization.internal.StringDescriptor
{{#isMapContainer}}
{{>serial_wrapper_response_map}}
{{/isMapContainer}}
-
- {{/operation}}
-
- {{#nonPublicApi}}internal {{/nonPublicApi}}companion object {
- internal fun setMappers(serializer: KotlinxSerializer) {
- {{#operation}}
- {{#hasBodyParam}}
- {{#bodyParam}}
- {{#isListContainer}}serializer.setMapper({{operationIdCamelCase}}Request::class, {{operationIdCamelCase}}Request.serializer()){{/isListContainer}}{{#isMapContainer}}serializer.setMapper({{operationIdCamelCase}}Request::class, {{operationIdCamelCase}}Request.serializer()){{/isMapContainer}}
- {{/bodyParam}}
- {{/hasBodyParam}}
- {{#isListContainer}}
- serializer.setMapper({{operationIdCamelCase}}Response::class, {{operationIdCamelCase}}Response.serializer())
- {{/isListContainer}}
- {{#isMapContainer}}
- serializer.setMapper({{operationIdCamelCase}}Response::class, {{operationIdCamelCase}}Response.serializer())
- {{/isMapContainer}}
- {{/operation}}
- }
- }
+{{/operation}}
}
{{/operations}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/ApiKeyAuth.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/ApiKeyAuth.kt.mustache
index 618fd7a88903..9141647d4a84 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/ApiKeyAuth.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/ApiKeyAuth.kt.mustache
@@ -1,16 +1,18 @@
package {{packageName}}.auth
-class ApiKeyAuth(private val location: String, val paramName: String) : Authentication {
+import {{packageName}}.infrastructure.Queries
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class ApiKeyAuth(private val location: String, val paramName: String) : Authentication {
var apiKey: String? = null
var apiKeyPrefix: String? = null
- override fun apply(query: MutableMap>, headers: MutableMap) {
- val key: String = apiKey ?: return
- val prefix: String? = apiKeyPrefix
- val value: String = if (prefix != null) "$prefix $key" else key
- when (location) {
- "query" -> query[paramName] = listOf(value)
- "header" -> headers[paramName] = value
+ override fun apply(queries: Queries, headers: MutableMap) {
+ val key: String = apiKey ?: return
+ val prefix: String? = apiKeyPrefix
+ val value: String = if (prefix != null) "$prefix $key" else key
+ when (location) {
+ "query" -> queries.add(paramName, value)
+ "header" -> headers[paramName] = value
+ }
}
- }
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/Authentication.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/Authentication.kt.mustache
index 1aab9156d98b..1873652b11b9 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/Authentication.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/Authentication.kt.mustache
@@ -1,13 +1,13 @@
package {{packageName}}.auth
-interface Authentication {
+import {{packageName}}.infrastructure.Queries
+{{#nonPublicApi}}internal {{/nonPublicApi}}interface Authentication {
/**
* Apply authentication settings to header and query params.
*
- * @param query Query parameters.
+ * @param queries Query parameters.
* @param headers Header parameters.
*/
- fun apply(query: MutableMap>, headers: MutableMap)
-
+ fun apply(queries: Queries, headers: MutableMap)
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBasicAuth.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBasicAuth.kt.mustache
index ef6c5888ae14..a9d6adabeabf 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBasicAuth.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBasicAuth.kt.mustache
@@ -1,17 +1,16 @@
package {{packageName}}.auth
-import io.ktor.util.InternalAPI
-import io.ktor.util.encodeBase64
+import {{packageName}}.infrastructure.Queries
+import {{packageName}}.infrastructure.toBase64
-class HttpBasicAuth : Authentication {
+{{#nonPublicApi}}internal {{/nonPublicApi}}class HttpBasicAuth : Authentication {
var username: String? = null
var password: String? = null
- @InternalAPI
- override fun apply(query: MutableMap>, headers: MutableMap) {
+ override fun apply(queries: Queries, headers: MutableMap) {
if (username == null && password == null) return
val str = (username ?: "") + ":" + (password ?: "")
- val auth = str.encodeBase64()
+ val auth = str.toBase64()
headers["Authorization"] = "Basic $auth"
}
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBearerAuth.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBearerAuth.kt.mustache
index 982389d09609..55806037e250 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBearerAuth.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/HttpBearerAuth.kt.mustache
@@ -1,9 +1,11 @@
package {{packageName}}.auth
-class HttpBearerAuth(private val scheme: String?) : Authentication {
+import {{packageName}}.infrastructure.Queries
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class HttpBearerAuth(private val scheme: String?) : Authentication {
var bearerToken: String? = null
- override fun apply(query: MutableMap>, headers: MutableMap) {
+ override fun apply(queries: Queries, headers: MutableMap) {
val token: String = bearerToken ?: return
headers["Authorization"] = (if (scheme != null) upperCaseBearer(scheme)!! + " " else "") + token
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/OAuth.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/OAuth.kt.mustache
index 98bb449a6096..b85b0226728e 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/OAuth.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/auth/OAuth.kt.mustache
@@ -1,9 +1,11 @@
package {{packageName}}.auth
-class OAuth : Authentication {
+import {{packageName}}.infrastructure.Queries
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class OAuth : Authentication {
var accessToken: String? = null
- override fun apply(query: MutableMap>, headers: MutableMap) {
+ override fun apply(queries: Queries, headers: MutableMap) {
val token: String = accessToken ?: return
headers["Authorization"] = "Bearer $token"
}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache
new file mode 100644
index 000000000000..863decf65625
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.kts.mustache
@@ -0,0 +1,123 @@
+plugins {
+ kotlin("multiplatform") version "1.4.0"
+ kotlin("plugin.serialization") version "1.4.0"
+}
+
+group = "{{groupId}}"
+version = "{{artifactVersion}}"
+
+val ktorVersion = "1.4.0"
+
+repositories {
+ jcenter()
+}
+
+kotlin {
+ /*
+ * To find out how to configure the targets, please follow the link:
+ * https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets
+ */
+ jvm {
+ val main by compilations.getting {
+ kotlinOptions {
+ // Setup the Kotlin compiler options for the 'main' compilation:
+ jvmTarget = "1.8"
+ }
+ }
+ }
+ ios {
+ binaries {
+ framework {
+ freeCompilerArgs = listOf("-Xobjc-generics")
+ }
+ }
+ }
+ js(BOTH) {
+ browser()
+ nodejs()
+ }
+
+ sourceSets {
+ val commonMain by getting {
+ kotlin.srcDir("src/common/main")
+
+ dependencies {
+ implementation(kotlin("stdlib-common"))
+ api("io.ktor:ktor-client-core:$ktorVersion")
+ api("io.ktor:ktor-client-json:$ktorVersion")
+ api("io.ktor:ktor-client-serialization:$ktorVersion")
+ }
+ }
+
+ val commonTest by getting {
+ kotlin.srcDir("src/common/test")
+
+ dependencies {
+ implementation(kotlin("test-common"))
+ implementation(kotlin("test-annotations-common"))
+ implementation("io.ktor:ktor-client-mock:$ktorVersion")
+ }
+ }
+
+ val jvmMain by getting {
+ kotlin.srcDir("src/jvm/main")
+
+ dependencies {
+ implementation(kotlin("stdlib-jdk8"))
+ api("io.ktor:ktor-client-core-jvm:$ktorVersion")
+ }
+ }
+
+ val jvmTest by getting {
+ kotlin.srcDir("src/jvm/test")
+
+ dependencies {
+ implementation(kotlin("test"))
+ implementation(kotlin("test-junit5"))
+ implementation("org.junit.jupiter:junit-jupiter:5.6.2")
+ implementation("io.ktor:ktor-client-apache:$ktorVersion")
+ implementation("io.ktor:ktor-client-mock-jvm:$ktorVersion")
+ }
+ }
+
+ val iosMain by getting {
+ kotlin.srcDir("src/ios/main")
+
+ dependencies {
+ implementation(kotlin("stdlib-native"))
+ api("io.ktor:ktor-client-ios:$ktorVersion")
+ }
+ }
+
+ val iosTest by getting {
+ kotlin.srcDir("src/ios/test")
+
+ dependencies {
+ implementation("io.ktor:ktor-client-mock-native:$ktorVersion")
+ }
+ }
+
+ val jsMain by getting {
+ kotlin.srcDir("src/js/main")
+
+ dependencies {
+ implementation(kotlin("stdlib-js"))
+ api("io.ktor:ktor-client-js:$ktorVersion")
+ }
+ }
+
+ val jsTest by getting {
+ kotlin.srcDir("src/js/test")
+
+ dependencies {
+ implementation("io.ktor:ktor-client-mock-js:$ktorVersion")
+ }
+ }
+ }
+}
+
+tasks {
+ named("jvmTest") {
+ useJUnitPlatform()
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.mustache
deleted file mode 100644
index dfc6736dc6d5..000000000000
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/build.gradle.mustache
+++ /dev/null
@@ -1,161 +0,0 @@
-apply plugin: 'kotlin-multiplatform'
-apply plugin: 'kotlinx-serialization'
-
-group '{{groupId}}'
-version '{{artifactVersion}}'
-
-ext {
- kotlin_version = '1.3.50'
- kotlinx_version = '1.1.0'
- coroutines_version = '1.3.1'
- serialization_version = '0.12.0'
- ktor_version = '1.2.4'
-}
-
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.50" // $kotlin_version
- classpath "org.jetbrains.kotlin:kotlin-serialization:1.3.50" // $kotlin_version
- }
-}
-
-repositories {
- jcenter()
-}
-
-kotlin {
- jvm()
- iosArm64() { binaries { framework { freeCompilerArgs.add("-Xobjc-generics") } } }
- iosX64() { binaries { framework { freeCompilerArgs.add("-Xobjc-generics") } } }
- js()
-
- sourceSets {
- commonMain {
- dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutines_version"
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"
- api "io.ktor:ktor-client-core:$ktor_version"
- api "io.ktor:ktor-client-json:$ktor_version"
- api "io.ktor:ktor-client-serialization:$ktor_version"
- }
- }
-
- commonTest {
- dependencies {
- implementation "org.jetbrains.kotlin:kotlin-test-common"
- implementation "org.jetbrains.kotlin:kotlin-test-annotations-common"
- implementation "io.ktor:ktor-client-mock:$ktor_version"
- }
- }
-
- jvmMain {
- dependsOn commonMain
- dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
- api "io.ktor:ktor-client-core-jvm:$ktor_version"
- api "io.ktor:ktor-client-json-jvm:$ktor_version"
- api "io.ktor:ktor-client-serialization-jvm:$ktor_version"
- }
- }
-
- jvmTest {
- dependsOn commonTest
- dependencies {
- implementation "org.jetbrains.kotlin:kotlin-test"
- implementation "org.jetbrains.kotlin:kotlin-test-junit"
- implementation "io.ktor:ktor-client-mock-jvm:$ktor_version"
- }
- }
-
- iosMain {
- dependsOn commonMain
- dependencies {
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutines_version"
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version"
- api "io.ktor:ktor-client-ios:$ktor_version"
- }
- }
-
- iosTest {
- dependsOn commonTest
- dependencies {
- implementation "io.ktor:ktor-client-mock-native:$ktor_version"
- }
- }
-
- iosArm64().compilations.main.defaultSourceSet {
- dependsOn iosMain
- dependencies {
- api "io.ktor:ktor-client-ios-iosarm64:$ktor_version"
- api "io.ktor:ktor-client-json-iosarm64:$ktor_version"
- api "io.ktor:ktor-client-serialization-iosarm64:$ktor_version"
- }
- }
-
- iosArm64().compilations.test.defaultSourceSet {
- dependsOn iosTest
- }
-
- iosX64().compilations.main.defaultSourceSet {
- dependsOn iosMain
- dependencies {
- api "io.ktor:ktor-client-ios-iosx64:$ktor_version"
- api "io.ktor:ktor-client-json-iosx64:$ktor_version"
- api "io.ktor:ktor-client-serialization-iosx64:$ktor_version"
- }
- }
-
- jsMain {
- dependsOn commonMain
- dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-js:$coroutines_version"
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version"
- api "io.ktor:ktor-client-js:$ktor_version"
- api "io.ktor:ktor-client-json-js:$ktor_version"
- api "io.ktor:ktor-client-serialization-js:$ktor_version"
- }
- }
-
- jsTest {
- dependsOn commonTest
- dependencies {
- implementation "io.ktor:ktor-client-mock-js:$ktor_version"
- implementation "io.ktor:ktor-client-js:$ktor_version"
- implementation "io.ktor:ktor-client-json:$ktor_version"
- implementation "io.ktor:ktor-client-serialization-js:$ktor_version"
- }
- }
-
- iosX64().compilations.test.defaultSourceSet {
- dependsOn iosTest
- }
-
- all {
- languageSettings {
- useExperimentalAnnotation('kotlin.Experimental')
- }
- }
- }
-}
-
-task iosTest {
- def device = project.findProperty("device")?.toString() ?: "iPhone 8"
- dependsOn 'linkDebugTestIosX64'
- group = JavaBasePlugin.VERIFICATION_GROUP
- description = "Execute unit tests on ${device} simulator"
- doLast {
- def binary = kotlin.targets.iosX64.binaries.getTest('DEBUG')
- exec { commandLine 'xcrun', 'simctl', 'spawn', device, binary.outputFile }
- }
-}
-
-configurations { // workaround for https://youtrack.jetbrains.com/issue/KT-27170
- compileClasspath
-}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.jar b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.jar
index 2c6137b87896..490fda8577df 100644
Binary files a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.jar and b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.jar differ
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.properties.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.properties.mustache
index ce3ca77db54b..8f38dbc2bfd8 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.properties.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradle-wrapper.properties.mustache
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradlew b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradlew
new file mode 100755
index 000000000000..2fe81a7d95e4
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradlew.bat b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradlew.bat
new file mode 100644
index 000000000000..62bd9b9ccefe
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/gradlew.bat
@@ -0,0 +1,103 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiAbstractions.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiAbstractions.kt.mustache
new file mode 100644
index 000000000000..36f44ff217f4
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiAbstractions.kt.mustache
@@ -0,0 +1,51 @@
+package {{packageName}}.infrastructure
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) {
+ "csv" -> ","
+ "tsv" -> "\t"
+ "pipe" -> "|"
+ "space" -> " "
+ else -> ""
+}
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}sealed class QueryParam {
+ data class Single(val value: String) : QueryParam()
+ data class Multi(val values: Iterable) : QueryParam()
+}
+
+{{#nonPublicApi}}internal {{/nonPublicApi}}class Queries(val queries: MutableMap = mutableMapOf()) {
+ constructor(queries: MutableMap = mutableMapOf(), config: Queries.() -> Unit): this(queries) {
+ config(this)
+ }
+
+ // Single
+ fun add(name: String, value: String?) {
+ if (value != null) {
+ queries[name] = QueryParam.Single(value)
+ }
+ }
+
+ fun add(name: String, value: Any?) {
+ if (value != null) {
+ queries[name] = QueryParam.Single(value.toString())
+ }
+ }
+
+ // For Iterables
+ fun addMulti(name: String, values: Iterable, collectionFormat: String) {
+ val transformed = values.filterNotNull().map { it.toString() }
+ queries[name] = when (collectionFormat) {
+ "multi" -> QueryParam.Multi(transformed)
+ else -> QueryParam.Single(transformed.joinToString(separator = collectionDelimiter(collectionFormat)))
+ }
+ }
+
+ // For Arrays
+ fun addMulti(name: String, values: Array, collectionFormat: String) =
+ addMulti(name, values.asIterable(), collectionFormat)
+
+ // For Maps
+ fun addMap(values: Map) {
+ queries.putAll(values.filterValues { it != null }.mapValues { QueryParam.Single(it.value.toString()) })
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClientBase.kt.mustache
similarity index 61%
rename from modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache
rename to modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClientBase.kt.mustache
index ae65921bb778..cf2c444566fb 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClient.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/ApiClientBase.kt.mustache
@@ -2,74 +2,50 @@ package {{packageName}}.infrastructure
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
-import io.ktor.client.call.call
import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.features.json.JsonFeature
-import io.ktor.client.features.json.JsonSerializer
import io.ktor.client.features.json.serializer.KotlinxSerializer
-import io.ktor.client.request.accept
import io.ktor.client.request.forms.FormDataContent
import io.ktor.client.request.forms.MultiPartFormDataContent
import io.ktor.client.request.header
import io.ktor.client.request.parameter
-import io.ktor.client.response.HttpResponse
+import io.ktor.client.request.request
+import io.ktor.client.statement.HttpResponse
import io.ktor.client.utils.EmptyContent
import io.ktor.http.*
import io.ktor.http.content.OutgoingContent
import io.ktor.http.content.PartData
-import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
-import {{apiPackage}}.*
-import {{modelPackage}}.*
import {{packageName}}.auth.*
-{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient(
+{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClientBase(
private val baseUrl: String,
httpClientEngine: HttpClientEngine?,
- serializer: KotlinxSerializer) {
-
- @UseExperimental(UnstableDefault::class)
- constructor(
- baseUrl: String,
- httpClientEngine: HttpClientEngine?,
- jsonConfiguration: JsonConfiguration) :
- this(baseUrl, httpClientEngine, KotlinxSerializer(Json(jsonConfiguration)))
-
- private val serializer: JsonSerializer by lazy {
- serializer.apply { setMappers(this) }.ignoreOutgoingContent()
- }
+ json: Json = Json {}
+) {
+ private val serializer = KotlinxSerializer(json)
private val client: HttpClient by lazy {
- val jsonConfig: JsonFeature.Config.() -> Unit = { this.serializer = this@ApiClient.serializer }
+ val jsonConfig: JsonFeature.Config.() -> Unit = { this.serializer = this@ApiClientBase.serializer }
val clientConfig: (HttpClientConfig<*>) -> Unit = { it.install(JsonFeature, jsonConfig) }
httpClientEngine?.let { HttpClient(it, clientConfig) } ?: HttpClient(clientConfig)
}
{{#hasAuthMethods}}
- private val authentications: kotlin.collections.Map by lazy {
- mapOf({{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
+ private val authentications: Map = mapOf({{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
"{{name}}" to HttpBasicAuth(){{/isBasicBasic}}{{^isBasicBasic}}
"{{name}}" to HttpBearerAuth("{{scheme}}"){{/isBasicBasic}}{{/isBasic}}{{#isApiKey}}
"{{name}}" to ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"){{/isApiKey}}{{#isOAuth}}
- "{{name}}" to OAuth(){{/isOAuth}}{{#hasMore}}, {{/hasMore}}{{/authMethods}})
- }
+ "{{name}}" to OAuth(){{/isOAuth}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}
+ )
{{/hasAuthMethods}}
+
{{^hasAuthMethods}}
- private val authentications: kotlin.collections.Map? = null
+ private val authentications: Map = mapOf()
{{/hasAuthMethods}}
{{#nonPublicApi}}internal {{/nonPublicApi}}companion object {
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
-
- private fun setMappers(serializer: KotlinxSerializer) {
- {{#apiInfo}}{{#apis}}
- {{classname}}.setMappers(serializer)
- {{/apis}}{{/apiInfo}}
- {{#models}}
- {{#model}}{{^isAlias}}serializer.setMapper({{modelPackage}}.{{classname}}::class, {{modelPackage}}.{{classname}}.{{#isEnum}}Serializer{{/isEnum}}{{^isEnum}}serializer(){{/isEnum}}){{/isAlias}}{{/model}}
- {{/models}}
- }
}
/**
@@ -78,7 +54,7 @@ import {{packageName}}.auth.*
* @param username Username
*/
fun setUsername(username: String) {
- val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
+ val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
?: throw Exception("No HTTP basic authentication configured")
auth.username = username
}
@@ -89,7 +65,7 @@ import {{packageName}}.auth.*
* @param password Password
*/
fun setPassword(password: String) {
- val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
+ val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
?: throw Exception("No HTTP basic authentication configured")
auth.password = password
}
@@ -101,7 +77,7 @@ import {{packageName}}.auth.*
* @param paramName The name of the API key parameter, or null or set the first key.
*/
fun setApiKey(apiKey: String, paramName: String? = null) {
- val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
+ val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
?: throw Exception("No API key authentication configured")
auth.apiKey = apiKey
}
@@ -113,7 +89,7 @@ import {{packageName}}.auth.*
* @param paramName The name of the API key parameter, or null or set the first key.
*/
fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) {
- val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
+ val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
?: throw Exception("No API key authentication configured")
auth.apiKeyPrefix = apiKeyPrefix
}
@@ -124,7 +100,7 @@ import {{packageName}}.auth.*
* @param accessToken Access token
*/
fun setAccessToken(accessToken: String) {
- val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
+ val auth = authentications.values.firstOrNull { it is OAuth } as OAuth?
?: throw Exception("No OAuth2 authentication configured")
auth.accessToken = accessToken
}
@@ -135,37 +111,40 @@ import {{packageName}}.auth.*
* @param bearerToken The bearer token.
*/
fun setBearerToken(bearerToken: String) {
- val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
+ val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
?: throw Exception("No Bearer authentication configured")
auth.bearerToken = bearerToken
}
- protected suspend fun multipartFormRequest(requestConfig: RequestConfig, body: kotlin.collections.List?, authNames: kotlin.collections.List): HttpResponse {
+ protected suspend fun multipartFormRequest(requestConfig: RequestConfig, body: List?, authNames: List): HttpResponse {
return request(requestConfig, MultiPartFormDataContent(body ?: listOf()), authNames)
}
- protected suspend fun urlEncodedFormRequest(requestConfig: RequestConfig, body: Parameters?, authNames: kotlin.collections.List): HttpResponse {
+ protected suspend fun urlEncodedFormRequest(requestConfig: RequestConfig, body: Parameters?, authNames: List): HttpResponse {
return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames)
}
- protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse {
+ protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: List): HttpResponse {
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
?: ContentType.Application.Json)
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
else request(requestConfig, authNames = authNames)
}
- protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List): HttpResponse {
+ protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent, authNames: List): HttpResponse {
requestConfig.updateForAuth(authNames)
val headers = requestConfig.headers
- return client.call {
+ return client.request {
this.url {
this.takeFrom(URLBuilder(baseUrl))
appendPath(requestConfig.path.trimStart('/').split('/'))
- requestConfig.query.forEach { query ->
- query.value.forEach { value ->
- parameter(query.key, value)
+ for ((name, value) in requestConfig.queries.queries) {
+ when (value) {
+ is QueryParam.Single -> parameter(name, value.value)
+ is QueryParam.Multi -> value.values.forEach {
+ parameter(name, it)
+ }
}
}
}
@@ -174,17 +153,17 @@ import {{packageName}}.auth.*
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
this.body = body
- }.response
+ }
}
- private fun RequestConfig.updateForAuth(authNames: kotlin.collections.List) {
+ private fun RequestConfig.updateForAuth(authNames: List) {
for (authName in authNames) {
- val auth = authentications?.get(authName) ?: throw Exception("Authentication undefined: $authName")
- auth.apply(query, headers)
+ val auth = authentications[authName] ?: throw Exception("Authentication undefined: $authName")
+ auth.apply(queries, headers)
}
}
- private fun URLBuilder.appendPath(components: kotlin.collections.List): URLBuilder = apply {
+ private fun URLBuilder.appendPath(components: List): URLBuilder = apply {
encodedPath = encodedPath.trimEnd('/') + components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() }
}
@@ -199,13 +178,3 @@ import {{packageName}}.auth.*
RequestMethod.OPTIONS -> HttpMethod.Options
}
}
-
-// https://github.com/ktorio/ktor/issues/851
-private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
-
-private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
- override fun write(data: Any): OutgoingContent {
- if (data is OutgoingContent) return data
- return delegate.write(data)
- }
-}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Base64ByteArray.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Base64ByteArray.kt.mustache
index 168cfc993c3b..d8042c19f764 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Base64ByteArray.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Base64ByteArray.kt.mustache
@@ -1,15 +1,21 @@
package {{packageName}}.infrastructure
-import kotlinx.serialization.*
-import kotlinx.serialization.internal.StringDescriptor
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
-@Serializable
-class Base64ByteArray(val value: ByteArray) {
- @Serializer(Base64ByteArray::class)
+@Serializable(with = Base64ByteArray.Companion::class)
+{{#nonPublicApi}}internal {{/nonPublicApi}}class Base64ByteArray(val value: ByteArray) {
companion object : KSerializer {
- override val descriptor = StringDescriptor.withName("Base64ByteArray")
- override fun serialize(encoder: Encoder, obj: Base64ByteArray) = encoder.encodeString(obj.value.encodeBase64())
- override fun deserialize(decoder: Decoder) = Base64ByteArray(decoder.decodeString().decodeBase64Bytes())
+ override val descriptor = PrimitiveSerialDescriptor("Base64ByteArray", PrimitiveKind.STRING)
+ override fun serialize(encoder: Encoder, value: Base64ByteArray): Unit =
+ encoder.encodeString(value.value.encodeBase64())
+
+ override fun deserialize(decoder: Decoder): Base64ByteArray =
+ Base64ByteArray(decoder.decodeString().decodeBase64Bytes())
}
override fun equals(other: Any?): Boolean {
@@ -26,4 +32,4 @@ class Base64ByteArray(val value: ByteArray) {
override fun toString(): String {
return "Base64ByteArray(${hex(value)})"
}
-}
\ No newline at end of file
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache
index b85013e647b2..7cd7d14721db 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/Bytes.kt.mustache
@@ -1,6 +1,6 @@
package {{packageName}}.infrastructure
-import kotlinx.io.core.*
+import io.ktor.utils.io.core.*
import kotlin.experimental.and
private val digits = "0123456789abcdef".toCharArray()
@@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
-internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
+internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeText(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
/**
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
@@ -32,7 +32,7 @@ internal fun hex(bytes: ByteArray): String {
result[resultIndex++] = digits[b and 0x0f]
}
- return String(result)
+ return result.concatToString()
}
/**
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache
index 87f27a5cf56f..a570d4a51389 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/HttpResponse.kt.mustache
@@ -4,8 +4,9 @@ import io.ktor.client.call.TypeInfo
import io.ktor.client.call.typeInfo
import io.ktor.http.Headers
import io.ktor.http.isSuccess
+import io.ktor.client.statement.HttpResponse as KtorHttpResponse
-{{#nonPublicApi}}internal {{/nonPublicApi}}open class HttpResponse(val response: io.ktor.client.response.HttpResponse, val provider: BodyProvider) {
+{{#nonPublicApi}}internal {{/nonPublicApi}}open class HttpResponse(val response: KtorHttpResponse, val provider: BodyProvider) {
val status: Int = response.status.value
val success: Boolean = response.status.isSuccess()
val headers: Map> = response.headers.mapEntries()
@@ -22,29 +23,30 @@ import io.ktor.http.isSuccess
}
{{#nonPublicApi}}internal {{/nonPublicApi}}interface BodyProvider {
- suspend fun body(response: io.ktor.client.response.HttpResponse): T
- suspend fun typedBody(response: io.ktor.client.response.HttpResponse, type: TypeInfo): V
+ suspend fun body(response: KtorHttpResponse): T
+ suspend fun typedBody(response: KtorHttpResponse, type: TypeInfo): V
}
{{#nonPublicApi}}internal {{/nonPublicApi}}class TypedBodyProvider(private val type: TypeInfo) : BodyProvider {
@Suppress("UNCHECKED_CAST")
- override suspend fun body(response: io.ktor.client.response.HttpResponse): T =
- response.call.receive(type) as T
+ override suspend fun body(response: KtorHttpResponse): T =
+ response.call.receive(type) as T
@Suppress("UNCHECKED_CAST")
- override suspend fun typedBody(response: io.ktor.client.response.HttpResponse, type: TypeInfo): V =
- response.call.receive(type) as V
+ override suspend fun typedBody(response: KtorHttpResponse, type: TypeInfo): V =
+ response.call.receive(type) as V
}
-{{#nonPublicApi}}internal {{/nonPublicApi}}class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider {
- override suspend fun body(response: io.ktor.client.response.HttpResponse): T =
- block(provider.body(response))
+{{#nonPublicApi}}internal {{/nonPublicApi}}class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) :
+ BodyProvider {
+ override suspend fun body(response: KtorHttpResponse): T =
+ block(provider.body(response))
- override suspend fun typedBody(response: io.ktor.client.response.HttpResponse, type: TypeInfo): V =
- provider.typedBody(response, type)
+ override suspend fun typedBody(response: KtorHttpResponse, type: TypeInfo): V =
+ provider.typedBody(response, type)
}
-{{#nonPublicApi}}internal {{/nonPublicApi}}inline fun io.ktor.client.response.HttpResponse.wrap(): HttpResponse =
+{{#nonPublicApi}}internal {{/nonPublicApi}}inline fun KtorHttpResponse.wrap(): HttpResponse =
HttpResponse(this, TypedBodyProvider(typeInfo()))
{{#nonPublicApi}}internal {{/nonPublicApi}}fun HttpResponse.map(block: T.() -> V): HttpResponse =
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/OctetByteArray.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/OctetByteArray.kt.mustache
index c23ac3ec0001..d6c10d8e5163 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/OctetByteArray.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/OctetByteArray.kt.mustache
@@ -1,14 +1,17 @@
package {{packageName}}.infrastructure
-import kotlinx.serialization.*
-import kotlinx.serialization.internal.StringDescriptor
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
-@Serializable
-class OctetByteArray(val value: ByteArray) {
- @Serializer(OctetByteArray::class)
+@Serializable(with = OctetByteArray.Companion::class)
+{{#nonPublicApi}}internal {{/nonPublicApi}}class OctetByteArray(val value: ByteArray) {
companion object : KSerializer {
- override val descriptor = StringDescriptor.withName("OctetByteArray")
- override fun serialize(encoder: Encoder, obj: OctetByteArray) = encoder.encodeString(hex(obj.value))
+ override val descriptor = PrimitiveSerialDescriptor("OctetByteArray", PrimitiveKind.STRING)
+ override fun serialize(encoder: Encoder, value: OctetByteArray) = encoder.encodeString(hex(value.value))
override fun deserialize(decoder: Decoder) = OctetByteArray(hex(decoder.decodeString()))
}
@@ -26,4 +29,4 @@ class OctetByteArray(val value: ByteArray) {
override fun toString(): String {
return "OctetByteArray(${hex(value)})"
}
-}
\ No newline at end of file
+}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/RequestConfig.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/RequestConfig.kt.mustache
new file mode 100644
index 000000000000..37b76a9bac4c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/RequestConfig.kt.mustache
@@ -0,0 +1,16 @@
+package {{packageName}}.infrastructure
+
+/**
+ * Defines a config object for a given request.
+ * NOTE: This object doesn't include 'body' because it
+ * allows for caching of the constructed object
+ * for many request definitions.
+ * NOTE: Headers is a Map because rfc2616 defines
+ * multi-valued headers as csv-only.
+ */
+{{#nonPublicApi}}internal {{/nonPublicApi}}data class RequestConfig(
+ val method: RequestMethod,
+ val path: String,
+ val headers: MutableMap = mutableMapOf(),
+ val queries: Queries = Queries()
+)
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/encoding.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/encoding.kt.mustache
new file mode 100644
index 000000000000..2ec8b39e3532
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/infrastructure/encoding.kt.mustache
@@ -0,0 +1,3 @@
+package {{packageName}}.infrastructure
+
+fun String.toBase64() = encodeToByteArray().encodeBase64()
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/jvmTest/Coroutine.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/jvmTest/Coroutine.kt.mustache
index 351c0120b7b1..5a4da4ee0f53 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/jvmTest/Coroutine.kt.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/jvmTest/Coroutine.kt.mustache
@@ -3,6 +3,7 @@
package util
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.runBlocking
import kotlin.coroutines.EmptyCoroutineContext
-internal actual fun runTest(block: suspend CoroutineScope.() -> T): T = kotlinx.coroutines.runBlocking(EmptyCoroutineContext, block)
+internal actual fun runTest(block: suspend CoroutineScope.() -> T): T = runBlocking(EmptyCoroutineContext, block)
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_list.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_list.mustache
index a44a242cbd2d..c387cdcaa186 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_list.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_list.mustache
@@ -1,10 +1,13 @@
- @Serializable
+ @Serializable(with = {{operationIdCamelCase}}Request.Companion::class)
private class {{operationIdCamelCase}}Request(val value: List<{{#bodyParam}}{{baseType}}{{/bodyParam}}>) {
- @Serializer({{operationIdCamelCase}}Request::class)
{{#nonPublicApi}}internal {{/nonPublicApi}}companion object : KSerializer<{{operationIdCamelCase}}Request> {
- private val serializer: KSerializer> = {{#bodyParam}}{{baseType}}{{/bodyParam}}.serializer().list
- override val descriptor = StringDescriptor.withName("{{operationIdCamelCase}}Request")
- override fun serialize(encoder: Encoder, obj: {{operationIdCamelCase}}Request) = serializer.serialize(encoder, obj.value)
- override fun deserialize(decoder: Decoder) = {{operationIdCamelCase}}Request(serializer.deserialize(decoder))
+ private val serializer = ListSerializer({{#bodyParam}}{{baseType}}{{/bodyParam}}.serializer())
+ override val descriptor = PrimitiveSerialDescriptor("{{operationIdCamelCase}}Request", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: {{operationIdCamelCase}}Request): Unit =
+ serializer.serialize(encoder, value.value)
+
+ override fun deserialize(decoder: Decoder): {{operationIdCamelCase}}Request =
+ {{operationIdCamelCase}}Request(serializer.deserialize(decoder))
}
- }
\ No newline at end of file
+ }
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_map.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_map.mustache
index 5dc6864aae82..011c57d6c662 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_map.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/serial_wrapper_request_map.mustache
@@ -3,8 +3,8 @@
@Serializer({{operationIdCamelCase}}Request::class)
{{#nonPublicApi}}internal {{/nonPublicApi}}companion object : KSerializer<{{operationIdCamelCase}}Request> {
private val serializer: KSerializer