diff --git a/.github/workflows/samples-kotlin-client.yaml b/.github/workflows/samples-kotlin-client.yaml
index 206cdbc0753e..3c86d9753afc 100644
--- a/.github/workflows/samples-kotlin-client.yaml
+++ b/.github/workflows/samples-kotlin-client.yaml
@@ -53,6 +53,8 @@ jobs:
- samples/client/petstore/kotlin-enum-integers-multiplatform
- samples/client/petstore/kotlin-array-simple-string-jvm-okhttp4
- samples/client/petstore/kotlin-array-simple-string-multiplatform
+ - samples/client/petstore/kotlin-array-nullable-items
+ - samples/client/petstore/kotlin-array-nullable-items-multiplatform
- samples/client/petstore/kotlin-bigdecimal-default-multiplatform
- samples/client/petstore/kotlin-bigdecimal-default-okhttp4
- samples/client/petstore/kotlin-jvm-jackson
diff --git a/bin/configs/kotlin-array-nullable-items-multiplatform.yaml b/bin/configs/kotlin-array-nullable-items-multiplatform.yaml
new file mode 100644
index 000000000000..341108d1d704
--- /dev/null
+++ b/bin/configs/kotlin-array-nullable-items-multiplatform.yaml
@@ -0,0 +1,8 @@
+generatorName: kotlin
+outputDir: samples/client/petstore/kotlin-array-nullable-items-multiplatform
+inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/kotlin-array-nullable-items.yaml
+templateDir: modules/openapi-generator/src/main/resources/kotlin-client
+additionalProperties:
+ artifactId: kotlin-array-nullable-items-multiplatform
+ library: multiplatform
+ dateLibrary: kotlinx-datetime
diff --git a/bin/configs/kotlin-array-nullable-items.yaml b/bin/configs/kotlin-array-nullable-items.yaml
new file mode 100644
index 000000000000..c75b95ea2e96
--- /dev/null
+++ b/bin/configs/kotlin-array-nullable-items.yaml
@@ -0,0 +1,6 @@
+generatorName: kotlin
+outputDir: samples/client/petstore/kotlin-array-nullable-items
+inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/kotlin-array-nullable-items.yaml
+templateDir: modules/openapi-generator/src/main/resources/kotlin-client
+additionalProperties:
+ artifactId: kotlin-array-nullable-items
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 abaf53a3b30a..ab4c5662f84b 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
@@ -21,4 +21,4 @@
{{#deprecated}}
@Deprecated(message = "This property is deprecated.")
{{/deprecated}}
- {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") {{/multiplatform}}{{#isInherited}}override {{/isInherited}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}? = {{^defaultValue}}null{{/defaultValue}}{{#defaultValue}}{{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{^multiplatform}}{{{dataType}}}("{{{defaultValue}}}"){{/multiplatform}}{{#multiplatform}}({{{defaultValue}}}).toDouble(){{/multiplatform}}{{/isNumber}}{{/defaultValue}}
\ No newline at end of file
+ {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") {{/multiplatform}}{{#isInherited}}override {{/isInherited}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}{{#items.isNullable}}?{{/items.isNullable}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}? = {{^defaultValue}}null{{/defaultValue}}{{#defaultValue}}{{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{^multiplatform}}{{{dataType}}}("{{{defaultValue}}}"){{/multiplatform}}{{#multiplatform}}({{{defaultValue}}}).toDouble(){{/multiplatform}}{{/isNumber}}{{/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 0d9ec6067c5a..ebb3444af1f1 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
@@ -21,4 +21,4 @@
{{#deprecated}}
@Deprecated(message = "This property is deprecated.")
{{/deprecated}}
- {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") @Required {{/multiplatform}}{{#isInherited}}override {{/isInherited}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{^multiplatform}}{{{dataType}}}("{{{defaultValue}}}"){{/multiplatform}}{{#multiplatform}}({{{defaultValue}}}).toDouble(){{/multiplatform}}{{/isNumber}}{{/defaultValue}}
\ No newline at end of file
+ {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") @Required {{/multiplatform}}{{#isInherited}}override {{/isInherited}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}{{#items.isNullable}}?{{/items.isNullable}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{^multiplatform}}{{{dataType}}}("{{{defaultValue}}}"){{/multiplatform}}{{#multiplatform}}({{{defaultValue}}}).toDouble(){{/multiplatform}}{{/isNumber}}{{/defaultValue}}
\ 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 8d1449fea9c8..ec99fea193f7 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
@@ -15,4 +15,4 @@
{{^isEnum}}{{^isArray}}{{^isPrimitiveType}}{{^isModel}}@Contextual {{/isModel}}{{/isPrimitiveType}}{{/isArray}}{{/isEnum}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}")
{{/kotlinx_serialization}}
{{/multiplatform}}
- {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") abstract {{/multiplatform}}{{#kotlinx_serialization}}abstract {{/kotlinx_serialization}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}?
\ No newline at end of file
+ {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") abstract {{/multiplatform}}{{#kotlinx_serialization}}abstract {{/kotlinx_serialization}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}{{#items.isNullable}}?{{/items.isNullable}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}?
\ No newline at end of file
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 d863cfea8ebb..df210ffa5954 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
@@ -15,4 +15,4 @@
{{^isEnum}}{{^isArray}}{{^isPrimitiveType}}{{^isModel}}@Contextual {{/isModel}}{{/isPrimitiveType}}{{/isArray}}{{/isEnum}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}")
{{/kotlinx_serialization}}
{{/multiplatform}}
- {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") @Required abstract {{/multiplatform}}{{#kotlinx_serialization}}abstract {{/kotlinx_serialization}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}
\ No newline at end of file
+ {{#multiplatform}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}") @Required abstract {{/multiplatform}}{{#kotlinx_serialization}}abstract {{/kotlinx_serialization}}{{>modelMutable}} {{{name}}}: {{#isArray}}{{#isList}}kotlin.collections.{{#modelMutable}}Mutable{{/modelMutable}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{^items.isEnum}}{{^items.isPrimitiveType}}{{^items.isModel}}{{#kotlinx_serialization}}@Contextual {{/kotlinx_serialization}}{{/items.isModel}}{{/items.isPrimitiveType}}{{{items.dataType}}}{{/items.isEnum}}{{#items.isEnum}}{{classname}}.{{{nameInPascalCase}}}{{/items.isEnum}}{{#items.isNullable}}?{{/items.isNullable}}>{{/isArray}}{{^isEnum}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isEnum}}{{#isEnum}}{{^isArray}}{{classname}}.{{{nameInPascalCase}}}{{/isArray}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/resources/3_0/kotlin/kotlin-array-nullable-items.yaml b/modules/openapi-generator/src/test/resources/3_0/kotlin/kotlin-array-nullable-items.yaml
new file mode 100644
index 000000000000..4e91c97fdc77
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/kotlin/kotlin-array-nullable-items.yaml
@@ -0,0 +1,33 @@
+openapi: 3.0.0
+info:
+ title: 'Kotlin client — nullable array items'
+ description: Regression spec for nullable items inside list/array properties.
+ version: latest
+paths:
+ '/':
+ get:
+ operationId: getModel
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ArrayWithNullableItemsModel'
+components:
+ schemas:
+ ArrayWithNullableItemsModel:
+ type: object
+ required:
+ - requiredItems
+ properties:
+ requiredItems:
+ type: array
+ items:
+ type: string
+ nullable: true
+ optionalItems:
+ type: array
+ items:
+ type: string
+ nullable: true
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator-ignore b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator-ignore
new file mode 100644
index 000000000000..7484ee590a38
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.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-array-nullable-items-multiplatform/.openapi-generator/FILES b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator/FILES
new file mode 100644
index 000000000000..b2f0a9d83a8d
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator/FILES
@@ -0,0 +1,24 @@
+README.md
+build.gradle.kts
+docs/ArrayWithNullableItemsModel.md
+docs/DefaultApi.md
+gradle/wrapper/gradle-wrapper.jar
+gradle/wrapper/gradle-wrapper.properties
+gradlew
+gradlew.bat
+settings.gradle.kts
+src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt
+src/commonMain/kotlin/org/openapitools/client/auth/ApiKeyAuth.kt
+src/commonMain/kotlin/org/openapitools/client/auth/Authentication.kt
+src/commonMain/kotlin/org/openapitools/client/auth/HttpBasicAuth.kt
+src/commonMain/kotlin/org/openapitools/client/auth/HttpBearerAuth.kt
+src/commonMain/kotlin/org/openapitools/client/auth/OAuth.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/Base64ByteArray.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/OctetByteArray.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
+src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
+src/commonMain/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator/VERSION b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator/VERSION
new file mode 100644
index 000000000000..ca7bf6e46889
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/.openapi-generator/VERSION
@@ -0,0 +1 @@
+7.23.0-SNAPSHOT
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/README.md b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/README.md
new file mode 100644
index 000000000000..28fab72186e7
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/README.md
@@ -0,0 +1,52 @@
+# org.openapitools.client - Kotlin client library for Kotlin client — nullable array items
+
+Regression spec for nullable items inside list/array properties.
+
+## Overview
+This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate an API client.
+
+- API version: latest
+- Package version:
+- Generator version: 7.23.0-SNAPSHOT
+- Build package: org.openapitools.codegen.languages.KotlinClientCodegen
+
+## Requires
+
+* Kotlin 2.2.20
+
+## 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://localhost*
+
+| Class | Method | HTTP request | Description |
+| ------------ | ------------- | ------------- | ------------- |
+| *DefaultApi* | [**getModel**](docs/DefaultApi.md#getmodel) | **GET** / | |
+
+
+
+## Documentation for Models
+
+ - [org.openapitools.client.models.ArrayWithNullableItemsModel](docs/ArrayWithNullableItemsModel.md)
+
+
+
+## Documentation for Authorization
+
+Endpoints do not require authorization.
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/build.gradle.kts b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/build.gradle.kts
new file mode 100644
index 000000000000..c545c8032baf
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/build.gradle.kts
@@ -0,0 +1,97 @@
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
+
+plugins {
+ kotlin("multiplatform") version "2.2.20" // kotlin_version
+ kotlin("plugin.serialization") version "2.2.20" // kotlin_version
+}
+
+group = "org.openapitools"
+version = "1.0.0"
+
+val kotlin_version = "2.2.20"
+val coroutines_version = "1.10.2"
+val serialization_version = "1.9.0"
+val ktor_version = "3.2.3"
+
+repositories {
+ mavenCentral()
+}
+
+kotlin {
+ jvm()
+ iosX64()
+ iosArm64()
+ iosSimulatorArm64()
+ js {
+ browser()
+ nodejs()
+ }
+
+ sourceSets {
+ commonMain {
+ dependencies {
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
+
+ api("io.ktor:ktor-client-core:$ktor_version")
+ api("io.ktor:ktor-client-serialization:$ktor_version")
+ api("io.ktor:ktor-client-content-negotiation:$ktor_version")
+ api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
+
+ api("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1")
+ }
+ }
+
+ commonTest {
+ dependencies {
+ implementation(kotlin("test"))
+ implementation("io.ktor:ktor-client-mock:$ktor_version")
+ }
+ }
+
+ jvmMain {
+ dependencies {
+ implementation(kotlin("stdlib-jdk7"))
+ implementation("io.ktor:ktor-client-cio-jvm:$ktor_version")
+ }
+ }
+
+ jvmTest {
+ dependencies {
+ implementation(kotlin("test-junit"))
+ }
+ }
+
+ iosMain {
+ dependencies {
+ api("io.ktor:ktor-client-ios:$ktor_version")
+ }
+ }
+
+ jsMain {
+ dependencies {
+ api("io.ktor:ktor-client-js:$ktor_version")
+ }
+ }
+
+ all {
+ languageSettings {
+ optIn("kotlin.time.ExperimentalTime")
+ }
+ }
+ }
+}
+
+tasks {
+ register("iosTest") {
+ val device = project.findProperty("device")?.toString() ?: "iPhone 8"
+ dependsOn("linkDebugTestIosX64")
+ group = JavaBasePlugin.VERIFICATION_GROUP
+ description = "Execute unit tests on ${device} simulator"
+ val binary = kotlin.targets.getByName("iosX64").binaries.getTest("DEBUG")
+ commandLine("xcrun", "simctl", "spawn", device, binary.outputFile)
+ }
+ register("test") {
+ dependsOn("allTests")
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/docs/ArrayWithNullableItemsModel.md b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/docs/ArrayWithNullableItemsModel.md
new file mode 100644
index 000000000000..b72190023de1
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/docs/ArrayWithNullableItemsModel.md
@@ -0,0 +1,11 @@
+
+# ArrayWithNullableItemsModel
+
+## Properties
+| Name | Type | Description | Notes |
+| ------------ | ------------- | ------------- | ------------- |
+| **requiredItems** | **kotlin.collections.List<kotlin.String?>** | | |
+| **optionalItems** | **kotlin.collections.List<kotlin.String?>** | | [optional] |
+
+
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/docs/DefaultApi.md b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/docs/DefaultApi.md
new file mode 100644
index 000000000000..b0698436ab42
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/docs/DefaultApi.md
@@ -0,0 +1,50 @@
+# DefaultApi
+
+All URIs are relative to *http://localhost*
+
+| Method | HTTP request | Description |
+| ------------- | ------------- | ------------- |
+| [**getModel**](DefaultApi.md#getModel) | **GET** / | |
+
+
+
+# **getModel**
+> ArrayWithNullableItemsModel getModel()
+
+
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = DefaultApi()
+try {
+ val result : ArrayWithNullableItemsModel = apiInstance.getModel()
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling DefaultApi#getModel")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling DefaultApi#getModel")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+This endpoint does not need any parameter.
+
+### Return type
+
+[**ArrayWithNullableItemsModel**](ArrayWithNullableItemsModel.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/json
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradle/wrapper/gradle-wrapper.jar b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000000..2c3521197d7c
Binary files /dev/null and b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradle/wrapper/gradle-wrapper.properties b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000000..7705927e949f
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradlew b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradlew
new file mode 100644
index 000000000000..51eb8bb47109
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+[ -h "$app_path" ]
+do
+ls=$( ls -ld "$app_path" )
+link=${ls#*' -> '}
+case $link in #(
+/*) app_path=$link ;; #(
+*) app_path=$APP_HOME$link ;;
+esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+echo "$*"
+} >&2
+
+die () {
+echo
+echo "$*"
+echo
+exit 1
+} >&2
+
+# 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 ;; #(
+MSYS* | 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
+if ! command -v java >/dev/null 2>&1
+then
+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
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+case $MAX_FD in #(
+max*)
+# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+# shellcheck disable=SC2039,SC3045
+MAX_FD=$( ulimit -H -n ) ||
+warn "Could not query maximum file descriptor limit"
+esac
+case $MAX_FD in #(
+'' | soft) :;; #(
+*)
+# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+# shellcheck disable=SC2039,SC3045
+ulimit -n "$MAX_FD" ||
+warn "Could not set maximum file descriptor limit to $MAX_FD"
+esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+# Now convert the arguments - kludge to limit ourselves to /bin/sh
+for arg do
+if
+case $arg in #(
+-*) false ;; # don't mess with options #(
+/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+[ -e "$t" ] ;; #(
+*) false ;;
+esac
+then
+arg=$( cygpath --path --ignore --mixed "$arg" )
+fi
+# Roll the args list around exactly as many times as the number of
+# args, so each arg winds up back in the position where it started, but
+# possibly modified.
+#
+# NB: a `for` loop captures its iteration list before it begins, so
+# changing the positional parameters here affects neither the number of
+# iterations, nor the values presented in `arg`.
+shift # remove old arg
+set -- "$@" "$arg" # push replacement arg
+done
+fi
+
+
+# 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"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+"-Dorg.gradle.appname=$APP_BASE_NAME" \
+-classpath "$CLASSPATH" \
+org.gradle.wrapper.GradleWrapperMain \
+"$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+xargs -n1 |
+sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+tr '\n' ' '
+)" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradlew.bat b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradlew.bat
new file mode 100644
index 000000000000..9d21a21834d5
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/gradlew.bat
@@ -0,0 +1,94 @@
+@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
+@rem SPDX-License-Identifier: Apache-2.0
+@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=.
+@rem This is normally unused
+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% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+: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 %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 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!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/settings.gradle.kts b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/settings.gradle.kts
new file mode 100644
index 000000000000..4e6e5356c112
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/settings.gradle.kts
@@ -0,0 +1 @@
+rootProject.name = "kotlin-array-nullable-items-multiplatform"
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt
new file mode 100644
index 000000000000..35774f6acb67
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt
@@ -0,0 +1,89 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.apis
+
+import org.openapitools.client.models.ArrayWithNullableItemsModel
+
+import org.openapitools.client.infrastructure.*
+import io.ktor.client.HttpClient
+import io.ktor.client.HttpClientConfig
+import io.ktor.client.request.forms.formData
+import io.ktor.client.engine.HttpClientEngine
+import kotlinx.serialization.json.Json
+import io.ktor.http.ParametersBuilder
+import io.ktor.http.Headers
+import io.ktor.http.HttpHeaders
+import io.ktor.http.ContentType
+import io.ktor.http.content.PartData
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+
+open class DefaultApi : ApiClient {
+
+ constructor(
+ baseUrl: String = ApiClient.BASE_URL,
+ httpClientEngine: HttpClientEngine? = null,
+ httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
+ jsonSerializer: Json = ApiClient.JSON_DEFAULT
+ ) : super(baseUrl = baseUrl, httpClientEngine = httpClientEngine, httpClientConfig = httpClientConfig, jsonBlock = jsonSerializer)
+
+ constructor(
+ baseUrl: String,
+ httpClient: HttpClient
+ ): super(baseUrl = baseUrl, httpClient = httpClient)
+
+ /**
+ *
+ *
+ * @return ArrayWithNullableItemsModel
+ */
+ @Suppress("UNCHECKED_CAST")
+ open suspend fun getModel(): HttpResponse {
+
+ val localVariableAuthNames = listOf()
+
+ val localVariableBody =
+ io.ktor.client.utils.EmptyContent
+
+ val localVariableQuery = mutableMapOf>()
+ val localVariableHeaders = mutableMapOf()
+
+ val localVariableConfig = RequestConfig(
+ RequestMethod.GET,
+ "/",
+ query = localVariableQuery,
+ headers = localVariableHeaders,
+ requiresAuthentication = false,
+ )
+
+ return request(
+ localVariableConfig,
+ localVariableBody,
+ localVariableAuthNames
+ ).wrap()
+ }
+
+
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/ApiKeyAuth.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/ApiKeyAuth.kt
new file mode 100644
index 000000000000..8bd8b59a8f82
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/ApiKeyAuth.kt
@@ -0,0 +1,16 @@
+package org.openapitools.client.auth
+
+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
+ }
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/Authentication.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/Authentication.kt
new file mode 100644
index 000000000000..2c5dfb4acc56
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/Authentication.kt
@@ -0,0 +1,13 @@
+package org.openapitools.client.auth
+
+interface Authentication {
+
+ /**
+ * Apply authentication settings to header and query params.
+ *
+ * @param query Query parameters.
+ * @param headers Header parameters.
+ */
+ fun apply(query: MutableMap>, headers: MutableMap)
+
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/HttpBasicAuth.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/HttpBasicAuth.kt
new file mode 100644
index 000000000000..b4aecdc99658
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/HttpBasicAuth.kt
@@ -0,0 +1,15 @@
+package org.openapitools.client.auth
+
+import kotlin.io.encoding.Base64
+
+class HttpBasicAuth : Authentication {
+ var username: String? = null
+ var password: String? = null
+
+ override fun apply(query: MutableMap>, headers: MutableMap) {
+ if (username == null && password == null) return
+ val str = (username ?: "") + ":" + (password ?: "")
+ val auth = Base64.encode(str.encodeToByteArray())
+ headers["Authorization"] = "Basic $auth"
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/HttpBearerAuth.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/HttpBearerAuth.kt
new file mode 100644
index 000000000000..a6fb285af5c3
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/HttpBearerAuth.kt
@@ -0,0 +1,14 @@
+package org.openapitools.client.auth
+
+class HttpBearerAuth(private val scheme: String?) : Authentication {
+ var bearerToken: String? = null
+
+ override fun apply(query: MutableMap>, headers: MutableMap) {
+ val token: String = bearerToken ?: return
+ headers["Authorization"] = (if (scheme != null) upperCaseBearer(scheme)!! + " " else "") + token
+ }
+
+ private fun upperCaseBearer(scheme: String): String? {
+ return if ("bearer".equals(scheme, ignoreCase = true)) "Bearer" else scheme
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/OAuth.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/OAuth.kt
new file mode 100644
index 000000000000..0e8f30f39383
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/auth/OAuth.kt
@@ -0,0 +1,10 @@
+package org.openapitools.client.auth
+
+class OAuth : Authentication {
+ var accessToken: String? = null
+
+ override fun apply(query: MutableMap>, headers: MutableMap) {
+ val token: String = accessToken ?: return
+ headers["Authorization"] = "Bearer $token"
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
new file mode 100644
index 000000000000..7fe8da468374
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
@@ -0,0 +1,23 @@
+package org.openapitools.client.infrastructure
+
+typealias MultiValueMap = MutableMap>
+
+fun collectionDelimiter(collectionFormat: String): String = when(collectionFormat) {
+ "csv" -> ","
+ "tsv" -> "\t"
+ "pipe" -> "|"
+ "space" -> " "
+ else -> ""
+}
+
+val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" }
+
+fun toMultiValue(items: Array, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List
+ = toMultiValue(items.asIterable(), collectionFormat, map)
+
+fun toMultiValue(items: Iterable, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List {
+ return when(collectionFormat) {
+ "multi" -> items.map(map)
+ else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map))
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
new file mode 100644
index 000000000000..081b4b08c51f
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
@@ -0,0 +1,188 @@
+package org.openapitools.client.infrastructure
+
+import io.ktor.client.HttpClient
+import io.ktor.client.HttpClientConfig
+import io.ktor.client.engine.HttpClientEngine
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.client.request.*
+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.statement.HttpResponse
+import io.ktor.http.ContentType
+import io.ktor.serialization.kotlinx.json.json
+import io.ktor.http.*
+import io.ktor.http.content.PartData
+import io.ktor.http.contentType
+import kotlin.Unit
+import kotlinx.serialization.json.Json
+
+import org.openapitools.client.auth.*
+
+open class ApiClient(
+ private val baseUrl: String
+) {
+
+ private lateinit var client: HttpClient
+
+ constructor(
+ baseUrl: String,
+ httpClientEngine: HttpClientEngine?,
+ httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
+ jsonBlock: Json,
+ ) : this(baseUrl = baseUrl) {
+ val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
+ {
+ it.install(ContentNegotiation) { json(jsonBlock) }
+ httpClientConfig?.invoke(it)
+ }
+ }
+
+ client = httpClientEngine?.let { HttpClient(it, clientConfig) } ?: HttpClient(clientConfig)
+ }
+
+ constructor(
+ baseUrl: String,
+ httpClient: HttpClient
+ ): this(baseUrl = baseUrl) {
+ this.client = httpClient
+ }
+
+ private val authentications: kotlin.collections.Map? = null
+
+ companion object {
+ const val BASE_URL: String = "http://localhost"
+ val JSON_DEFAULT: Json = Json {
+ ignoreUnknownKeys = true
+ prettyPrint = true
+ isLenient = true
+ }
+ protected val UNSAFE_HEADERS: List = listOf(HttpHeaders.ContentType)
+ }
+
+ /**
+ * Set the username for the first HTTP basic authentication.
+ *
+ * @param username Username
+ */
+ fun setUsername(username: String) {
+ val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
+ ?: throw Exception("No HTTP basic authentication configured")
+ auth.username = username
+ }
+
+ /**
+ * Set the password for the first HTTP basic authentication.
+ *
+ * @param password Password
+ */
+ fun setPassword(password: String) {
+ val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
+ ?: throw Exception("No HTTP basic authentication configured")
+ auth.password = password
+ }
+
+ /**
+ * Set the API key value for the first API key authentication.
+ *
+ * @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) {
+ 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
+ }
+
+ /**
+ * Set the API key prefix for the first API key authentication.
+ *
+ * @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) {
+ 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
+ }
+
+ /**
+ * Set the access token for the first OAuth2 authentication.
+ *
+ * @param accessToken Access token
+ */
+ fun setAccessToken(accessToken: String) {
+ val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
+ ?: throw Exception("No OAuth2 authentication configured")
+ auth.accessToken = accessToken
+ }
+
+ /**
+ * Set the access token for the first Bearer authentication.
+ *
+ * @param bearerToken The bearer token.
+ */
+ fun setBearerToken(bearerToken: String) {
+ 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 {
+ return request(requestConfig, MultiPartFormDataContent(body ?: listOf()), authNames)
+ }
+
+ protected suspend fun urlEncodedFormRequest(requestConfig: RequestConfig, body: Parameters?, authNames: kotlin.collections.List): HttpResponse {
+ return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames)
+ }
+
+ protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames)
+
+ protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse {
+ requestConfig.updateForAuth(authNames)
+ val headers = requestConfig.headers
+
+ 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)
+ }
+ }
+ }
+ this.method = requestConfig.method.httpMethod
+ headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
+ if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) {
+ val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
+ ?: ContentType.Application.Json)
+ this.contentType(contentType)
+ this.setBody(body)
+ }
+ }
+ }
+
+ private fun RequestConfig.updateForAuth(authNames: kotlin.collections.List) {
+ for (authName in authNames) {
+ val auth = authentications?.get(authName) ?: throw Exception("Authentication undefined: $authName")
+ auth.apply(query, headers)
+ }
+ }
+
+ private fun URLBuilder.appendPath(components: kotlin.collections.List): URLBuilder = apply {
+ encodedPath = encodedPath.trimEnd('/') + components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() }
+ }
+
+ private val RequestMethod.httpMethod: HttpMethod
+ get() = when (this) {
+ RequestMethod.DELETE -> HttpMethod.Delete
+ RequestMethod.GET -> HttpMethod.Get
+ RequestMethod.HEAD -> HttpMethod.Head
+ RequestMethod.PATCH -> HttpMethod.Patch
+ RequestMethod.PUT -> HttpMethod.Put
+ RequestMethod.POST -> HttpMethod.Post
+ RequestMethod.OPTIONS -> HttpMethod.Options
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Base64ByteArray.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Base64ByteArray.kt
new file mode 100644
index 000000000000..0fda8e759f0c
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/Base64ByteArray.kt
@@ -0,0 +1,30 @@
+package org.openapitools.client.infrastructure
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlin.io.encoding.Base64
+
+@Serializable(Base64ByteArray.Companion::class)
+class Base64ByteArray(val value: ByteArray) {
+ companion object : KSerializer {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Base64ByteArray", PrimitiveKind.STRING)
+ override fun serialize(encoder: Encoder, value: Base64ByteArray): Unit = encoder.encodeString(Base64.encode(value.value))
+ override fun deserialize(decoder: Decoder): Base64ByteArray = Base64ByteArray(Base64.decode(decoder.decodeString()))
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+ other as Base64ByteArray
+ return value.contentEquals(other.value)
+ }
+
+ override fun hashCode(): Int {
+ return value.contentHashCode()
+ }
+
+ override fun toString(): String {
+ return "Base64ByteArray(${value.toHexString()})"
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt
new file mode 100644
index 000000000000..4285d605ea62
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt
@@ -0,0 +1,51 @@
+package org.openapitools.client.infrastructure
+
+import io.ktor.http.Headers
+import io.ktor.http.isSuccess
+import io.ktor.util.reflect.TypeInfo
+import io.ktor.util.reflect.typeInfo
+
+open class HttpResponse(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider) {
+ val status: Int = response.status.value
+ val success: Boolean = response.status.isSuccess()
+ val headers: Map> = response.headers.mapEntries()
+ suspend fun body(): T = provider.body(response)
+ suspend fun typedBody(type: TypeInfo): V = provider.typedBody(response, type)
+
+ companion object {
+ private fun Headers.mapEntries(): Map> {
+ val result = mutableMapOf>()
+ entries().forEach { result[it.key] = it.value }
+ return result
+ }
+ }
+}
+
+interface BodyProvider {
+ suspend fun body(response: io.ktor.client.statement.HttpResponse): T
+ suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V
+}
+
+class TypedBodyProvider(private val type: TypeInfo) : BodyProvider {
+ @Suppress("UNCHECKED_CAST")
+ override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
+ response.call.body(type) as T
+
+ @Suppress("UNCHECKED_CAST")
+ override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
+ response.call.body(type) as V
+}
+
+class MappedBodyProvider(private val provider: BodyProvider, private val block: S.() -> T) : BodyProvider {
+ override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
+ block(provider.body(response))
+
+ override suspend fun typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
+ provider.typedBody(response, type)
+}
+
+inline fun io.ktor.client.statement.HttpResponse.wrap(): HttpResponse =
+ HttpResponse(this, TypedBodyProvider(typeInfo()))
+
+fun HttpResponse.map(block: T.() -> V): HttpResponse =
+ HttpResponse(response, MappedBodyProvider(provider, block))
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/OctetByteArray.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/OctetByteArray.kt
new file mode 100644
index 000000000000..5c4b29cd595f
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/OctetByteArray.kt
@@ -0,0 +1,29 @@
+package org.openapitools.client.infrastructure
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+
+@Serializable(OctetByteArray.Companion::class)
+class OctetByteArray(val value: ByteArray) {
+ companion object : KSerializer {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("OctetByteArray", PrimitiveKind.STRING)
+ override fun serialize(encoder: Encoder, value: OctetByteArray): Unit = encoder.encodeString(value.value.toHexString())
+ override fun deserialize(decoder: Decoder): OctetByteArray = OctetByteArray(decoder.decodeString().hexToByteArray())
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+ other as OctetByteArray
+ return value.contentEquals(other.value)
+ }
+
+ override fun hashCode(): Int {
+ return value.contentHashCode()
+ }
+
+ override fun toString(): String {
+ return "OctetByteArray(${value.toHexString()})"
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/PartConfig.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
new file mode 100644
index 000000000000..c2a5c99ec7e6
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Defines a config object for a given part of a multi-part request.
+ * NOTE: Headers is a Map because rfc2616 defines
+ * multi-valued headers as csv-only.
+ *
+ * @property headers The headers for this part
+ * @property body The body content for this part
+ * @property serializer Optional custom serializer for JSON content. When provided, this will be
+ * used instead of the default serialization for parts with application/json
+ * content-type. This allows capturing type information at the call site to
+ * avoid issues with type erasure in kotlinx.serialization.
+ */
+data class PartConfig(
+ val headers: MutableMap = mutableMapOf(),
+ val body: T? = null,
+ val serializer: ((Any?) -> String)? = null
+)
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
new file mode 100644
index 000000000000..6578b9381b78
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.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.
+ */
+data class RequestConfig(
+ val method: RequestMethod,
+ val path: String,
+ val headers: MutableMap = mutableMapOf(),
+ val params: MutableMap = mutableMapOf(),
+ val query: MutableMap> = mutableMapOf(),
+ val requiresAuthentication: Boolean,
+ val body: T? = null
+)
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
new file mode 100644
index 000000000000..beb56f07cdde
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
@@ -0,0 +1,8 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Provides enumerated HTTP verbs
+ */
+enum class RequestMethod {
+ GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt
new file mode 100644
index 000000000000..f4d39b12519b
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt
@@ -0,0 +1,49 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.models
+
+
+import kotlinx.serialization.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+
+/**
+ *
+ *
+ * @param requiredItems
+ * @param optionalItems
+ */
+@Serializable
+
+data class ArrayWithNullableItemsModel (
+
+ @SerialName(value = "requiredItems") @Required val requiredItems: kotlin.collections.List,
+
+ @SerialName(value = "optionalItems") val optionalItems: kotlin.collections.List? = null
+
+) {
+
+
+}
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt
new file mode 100644
index 000000000000..d2700e179dd5
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt
@@ -0,0 +1,45 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.apis
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+
+import org.openapitools.client.apis.DefaultApi
+import org.openapitools.client.models.ArrayWithNullableItemsModel
+
+class DefaultApiTest : ShouldSpec() {
+ init {
+ // uncomment below to create an instance of DefaultApi
+ //val apiInstance = DefaultApi()
+
+ // to test getModel
+ should("test getModel") {
+ // uncomment below to test getModel
+ //val result : ArrayWithNullableItemsModel = apiInstance.getModel()
+ //result shouldBe ("TODO")
+ }
+
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/test/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModelTest.kt b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/test/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModelTest.kt
new file mode 100644
index 000000000000..c99c9d5e8b92
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items-multiplatform/src/test/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModelTest.kt
@@ -0,0 +1,49 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.models
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+
+import org.openapitools.client.models.ArrayWithNullableItemsModel
+
+class ArrayWithNullableItemsModelTest : ShouldSpec() {
+ init {
+ // uncomment below to create an instance of ArrayWithNullableItemsModel
+ //val modelInstance = ArrayWithNullableItemsModel()
+
+ // to test the property `requiredItems`
+ should("test requiredItems") {
+ // uncomment below to test the property
+ //modelInstance.requiredItems shouldBe ("TODO")
+ }
+
+ // to test the property `optionalItems`
+ should("test optionalItems") {
+ // uncomment below to test the property
+ //modelInstance.optionalItems shouldBe ("TODO")
+ }
+
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator-ignore b/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator-ignore
new file mode 100644
index 000000000000..7484ee590a38
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/.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-array-nullable-items/.openapi-generator/FILES b/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator/FILES
new file mode 100644
index 000000000000..39fe24c105ab
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator/FILES
@@ -0,0 +1,28 @@
+README.md
+build.gradle
+docs/ArrayWithNullableItemsModel.md
+docs/DefaultApi.md
+gradle/wrapper/gradle-wrapper.jar
+gradle/wrapper/gradle-wrapper.properties
+gradlew
+gradlew.bat
+settings.gradle
+src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt
+src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt
+src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
+src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
+src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
+src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt
+src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
+src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt
+src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt
+src/main/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt
diff --git a/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator/VERSION b/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator/VERSION
new file mode 100644
index 000000000000..ca7bf6e46889
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/.openapi-generator/VERSION
@@ -0,0 +1 @@
+7.23.0-SNAPSHOT
diff --git a/samples/client/petstore/kotlin-array-nullable-items/README.md b/samples/client/petstore/kotlin-array-nullable-items/README.md
new file mode 100644
index 000000000000..293251e725c0
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/README.md
@@ -0,0 +1,61 @@
+# org.openapitools.client - Kotlin client library for Kotlin client — nullable array items
+
+Regression spec for nullable items inside list/array properties.
+
+## Overview
+This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate an API client.
+
+- API version: latest
+- Package version:
+- Generator version: 7.23.0-SNAPSHOT
+- Build package: org.openapitools.codegen.languages.KotlinClientCodegen
+
+## Requires
+
+* Kotlin 2.2.20
+* Gradle 8.14
+
+## Build
+
+First, create the gradle wrapper script:
+
+```
+gradle wrapper
+```
+
+Then, run:
+
+```
+./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.
+* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets.
+
+
+## Documentation for API Endpoints
+
+All URIs are relative to *http://localhost*
+
+| Class | Method | HTTP request | Description |
+| ------------ | ------------- | ------------- | ------------- |
+| *DefaultApi* | [**getModel**](docs/DefaultApi.md#getmodel) | **GET** / | |
+
+
+
+## Documentation for Models
+
+ - [org.openapitools.client.models.ArrayWithNullableItemsModel](docs/ArrayWithNullableItemsModel.md)
+
+
+
+## Documentation for Authorization
+
+Endpoints do not require authorization.
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items/build.gradle b/samples/client/petstore/kotlin-array-nullable-items/build.gradle
new file mode 100644
index 000000000000..54f27f1a99bb
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/build.gradle
@@ -0,0 +1,77 @@
+group 'org.openapitools'
+version '1.0.0'
+
+wrapper {
+ gradleVersion = '8.14.3'
+ distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
+}
+
+buildscript {
+ ext.kotlin_version = '2.2.20'
+ ext.spotless_version = "7.2.1"
+
+ repositories {
+ maven { url "https://repo1.maven.org/maven2" }
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.diffplug.spotless:spotless-plugin-gradle:$spotless_version"
+ }
+}
+
+apply plugin: 'kotlin'
+apply plugin: 'maven-publish'
+apply plugin: 'com.diffplug.spotless'
+
+repositories {
+ maven { url "https://repo1.maven.org/maven2" }
+}
+
+// Use spotless plugin to automatically format code, remove unused import, etc
+// To apply changes directly to the file, run `gradlew spotlessApply`
+// Ref: https://github.com/diffplug/spotless/tree/main/plugin-gradle
+spotless {
+ // comment out below to run spotless as part of the `check` task
+ enforceCheck false
+
+ format 'misc', {
+ // define the files (e.g. '*.gradle', '*.md') to apply `misc` to
+ target '.gitignore'
+
+ // define the steps to apply to those files
+ trimTrailingWhitespace()
+ indentWithSpaces() // Takes an integer argument if you don't like 4
+ endWithNewline()
+ }
+ kotlin {
+ ktfmt()
+ }
+}
+
+test {
+ useJUnitPlatform()
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+ implementation "com.squareup.moshi:moshi-kotlin:1.15.2"
+ implementation "com.squareup.moshi:moshi-adapters:1.15.2"
+ implementation "com.squareup.okhttp3:okhttp:5.1.0"
+ testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
+}
+
+java {
+ withSourcesJar()
+}
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ groupId = 'org.openapitools'
+ artifactId = 'kotlin-array-nullable-items'
+ version = '1.0.0'
+ from components.java
+ }
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/docs/ArrayWithNullableItemsModel.md b/samples/client/petstore/kotlin-array-nullable-items/docs/ArrayWithNullableItemsModel.md
new file mode 100644
index 000000000000..b72190023de1
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/docs/ArrayWithNullableItemsModel.md
@@ -0,0 +1,11 @@
+
+# ArrayWithNullableItemsModel
+
+## Properties
+| Name | Type | Description | Notes |
+| ------------ | ------------- | ------------- | ------------- |
+| **requiredItems** | **kotlin.collections.List<kotlin.String?>** | | |
+| **optionalItems** | **kotlin.collections.List<kotlin.String?>** | | [optional] |
+
+
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items/docs/DefaultApi.md b/samples/client/petstore/kotlin-array-nullable-items/docs/DefaultApi.md
new file mode 100644
index 000000000000..b0698436ab42
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/docs/DefaultApi.md
@@ -0,0 +1,50 @@
+# DefaultApi
+
+All URIs are relative to *http://localhost*
+
+| Method | HTTP request | Description |
+| ------------- | ------------- | ------------- |
+| [**getModel**](DefaultApi.md#getModel) | **GET** / | |
+
+
+
+# **getModel**
+> ArrayWithNullableItemsModel getModel()
+
+
+
+### Example
+```kotlin
+// Import classes:
+//import org.openapitools.client.infrastructure.*
+//import org.openapitools.client.models.*
+
+val apiInstance = DefaultApi()
+try {
+ val result : ArrayWithNullableItemsModel = apiInstance.getModel()
+ println(result)
+} catch (e: ClientException) {
+ println("4xx response calling DefaultApi#getModel")
+ e.printStackTrace()
+} catch (e: ServerException) {
+ println("5xx response calling DefaultApi#getModel")
+ e.printStackTrace()
+}
+```
+
+### Parameters
+This endpoint does not need any parameter.
+
+### Return type
+
+[**ArrayWithNullableItemsModel**](ArrayWithNullableItemsModel.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/json
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items/gradle/wrapper/gradle-wrapper.jar b/samples/client/petstore/kotlin-array-nullable-items/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000000..2c3521197d7c
Binary files /dev/null and b/samples/client/petstore/kotlin-array-nullable-items/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/samples/client/petstore/kotlin-array-nullable-items/gradle/wrapper/gradle-wrapper.properties b/samples/client/petstore/kotlin-array-nullable-items/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000000..7705927e949f
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/samples/client/petstore/kotlin-array-nullable-items/gradlew b/samples/client/petstore/kotlin-array-nullable-items/gradlew
new file mode 100644
index 000000000000..51eb8bb47109
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+[ -h "$app_path" ]
+do
+ls=$( ls -ld "$app_path" )
+link=${ls#*' -> '}
+case $link in #(
+/*) app_path=$link ;; #(
+*) app_path=$APP_HOME$link ;;
+esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+echo "$*"
+} >&2
+
+die () {
+echo
+echo "$*"
+echo
+exit 1
+} >&2
+
+# 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 ;; #(
+MSYS* | 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
+if ! command -v java >/dev/null 2>&1
+then
+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
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+case $MAX_FD in #(
+max*)
+# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+# shellcheck disable=SC2039,SC3045
+MAX_FD=$( ulimit -H -n ) ||
+warn "Could not query maximum file descriptor limit"
+esac
+case $MAX_FD in #(
+'' | soft) :;; #(
+*)
+# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+# shellcheck disable=SC2039,SC3045
+ulimit -n "$MAX_FD" ||
+warn "Could not set maximum file descriptor limit to $MAX_FD"
+esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+# Now convert the arguments - kludge to limit ourselves to /bin/sh
+for arg do
+if
+case $arg in #(
+-*) false ;; # don't mess with options #(
+/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+[ -e "$t" ] ;; #(
+*) false ;;
+esac
+then
+arg=$( cygpath --path --ignore --mixed "$arg" )
+fi
+# Roll the args list around exactly as many times as the number of
+# args, so each arg winds up back in the position where it started, but
+# possibly modified.
+#
+# NB: a `for` loop captures its iteration list before it begins, so
+# changing the positional parameters here affects neither the number of
+# iterations, nor the values presented in `arg`.
+shift # remove old arg
+set -- "$@" "$arg" # push replacement arg
+done
+fi
+
+
+# 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"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+"-Dorg.gradle.appname=$APP_BASE_NAME" \
+-classpath "$CLASSPATH" \
+org.gradle.wrapper.GradleWrapperMain \
+"$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+xargs -n1 |
+sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+tr '\n' ' '
+)" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/samples/client/petstore/kotlin-array-nullable-items/gradlew.bat b/samples/client/petstore/kotlin-array-nullable-items/gradlew.bat
new file mode 100644
index 000000000000..9d21a21834d5
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/gradlew.bat
@@ -0,0 +1,94 @@
+@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
+@rem SPDX-License-Identifier: Apache-2.0
+@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=.
+@rem This is normally unused
+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% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+: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 %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 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!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/client/petstore/kotlin-array-nullable-items/settings.gradle b/samples/client/petstore/kotlin-array-nullable-items/settings.gradle
new file mode 100644
index 000000000000..73ff4129acdf
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'kotlin-array-nullable-items'
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
new file mode 100644
index 000000000000..66b89498f839
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
@@ -0,0 +1,129 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.apis
+
+import java.io.IOException
+import okhttp3.Call
+import okhttp3.HttpUrl
+
+import org.openapitools.client.models.ArrayWithNullableItemsModel
+
+import com.squareup.moshi.Json
+
+import org.openapitools.client.infrastructure.ApiClient
+import org.openapitools.client.infrastructure.ApiResponse
+import org.openapitools.client.infrastructure.ClientException
+import org.openapitools.client.infrastructure.ClientError
+import org.openapitools.client.infrastructure.ServerException
+import org.openapitools.client.infrastructure.ServerError
+import org.openapitools.client.infrastructure.MultiValueMap
+import org.openapitools.client.infrastructure.PartConfig
+import org.openapitools.client.infrastructure.RequestConfig
+import org.openapitools.client.infrastructure.RequestMethod
+import org.openapitools.client.infrastructure.ResponseType
+import org.openapitools.client.infrastructure.Success
+import org.openapitools.client.infrastructure.toMultiValue
+
+open class DefaultApi(basePath: kotlin.String = defaultBasePath, client: Call.Factory = ApiClient.defaultClient) : ApiClient(basePath, client) {
+ companion object {
+ @JvmStatic
+ val defaultBasePath: String by lazy {
+ System.getProperties().getProperty(ApiClient.BASE_URL_KEY, "http://localhost")
+ }
+ }
+
+ /**
+ * GET /
+ *
+ *
+ * @return ArrayWithNullableItemsModel
+ * @throws IllegalStateException If the request is not correctly configured
+ * @throws IOException Rethrows the OkHttp execute method exception
+ * @throws UnsupportedOperationException If the API returns an informational or redirection response
+ * @throws ClientException If the API returns a client error response
+ * @throws ServerException If the API returns a server error response
+ */
+ @Suppress("UNCHECKED_CAST")
+ @Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class)
+ fun getModel() : ArrayWithNullableItemsModel {
+ val localVarResponse = getModelWithHttpInfo()
+
+ return when (localVarResponse.responseType) {
+ ResponseType.Success -> (localVarResponse as Success<*>).data as ArrayWithNullableItemsModel
+ ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
+ ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
+ ResponseType.ClientError -> {
+ val localVarError = localVarResponse as ClientError<*>
+ throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
+ }
+ ResponseType.ServerError -> {
+ val localVarError = localVarResponse as ServerError<*>
+ throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()} ${localVarError.body}", localVarError.statusCode, localVarResponse)
+ }
+ }
+ }
+
+ /**
+ * GET /
+ *
+ *
+ * @return ApiResponse
+ * @throws IllegalStateException If the request is not correctly configured
+ * @throws IOException Rethrows the OkHttp execute method exception
+ */
+ @Suppress("UNCHECKED_CAST")
+ @Throws(IllegalStateException::class, IOException::class)
+ fun getModelWithHttpInfo() : ApiResponse {
+ val localVariableConfig = getModelRequestConfig()
+
+ return request(
+ localVariableConfig
+ )
+ }
+
+ /**
+ * To obtain the request config of the operation getModel
+ *
+ * @return RequestConfig
+ */
+ fun getModelRequestConfig() : RequestConfig {
+ val localVariableBody = null
+ val localVariableQuery: MultiValueMap = mutableMapOf()
+ val localVariableHeaders: MutableMap = mutableMapOf()
+ localVariableHeaders["Accept"] = "application/json"
+
+ return RequestConfig(
+ method = RequestMethod.GET,
+ path = "/",
+ query = localVariableQuery,
+ headers = localVariableHeaders,
+ requiresAuthentication = false,
+ body = localVariableBody
+ )
+ }
+
+
+ private fun encodeURIComponent(uriComponent: kotlin.String): kotlin.String =
+ HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments[0]
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
new file mode 100644
index 000000000000..7fe8da468374
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
@@ -0,0 +1,23 @@
+package org.openapitools.client.infrastructure
+
+typealias MultiValueMap = MutableMap>
+
+fun collectionDelimiter(collectionFormat: String): String = when(collectionFormat) {
+ "csv" -> ","
+ "tsv" -> "\t"
+ "pipe" -> "|"
+ "space" -> " "
+ else -> ""
+}
+
+val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" }
+
+fun toMultiValue(items: Array, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List
+ = toMultiValue(items.asIterable(), collectionFormat, map)
+
+fun toMultiValue(items: Iterable, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List {
+ return when(collectionFormat) {
+ "multi" -> items.map(map)
+ else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map))
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
new file mode 100644
index 000000000000..0197390a824a
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
@@ -0,0 +1,467 @@
+package org.openapitools.client.infrastructure
+
+import okhttp3.OkHttpClient
+import okhttp3.RequestBody
+import okhttp3.RequestBody.Companion.asRequestBody
+import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.FormBody
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import okhttp3.ResponseBody
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.Request
+import okhttp3.Headers
+import okhttp3.Headers.Builder
+import okhttp3.Headers.Companion.toHeaders
+import okhttp3.MultipartBody
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.Response
+import java.io.BufferedWriter
+import java.io.File
+import java.io.FileWriter
+import java.io.IOException
+import java.net.URLConnection
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.LocalTime
+import java.time.OffsetDateTime
+import java.time.OffsetTime
+import java.util.Locale
+import java.util.regex.Pattern
+import com.squareup.moshi.adapter
+
+val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody()
+
+open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClient) {
+ companion object {
+ protected const val CONTENT_TYPE: String = "Content-Type"
+ @Deprecated(
+ message = "Please use the capitalized constant `CONTENT_TYPE` instead.",
+ replaceWith = ReplaceWith("CONTENT_TYPE")
+ )
+ protected const val ContentType: String = CONTENT_TYPE
+
+ protected const val ACCEPT: String = "Accept"
+ @Deprecated(
+ message = "Please use the capitalized constant `ACCEPT` instead.",
+ replaceWith = ReplaceWith("ACCEPT")
+ )
+ protected const val Accept: String = ACCEPT
+
+ protected const val AUTHORIZATION: String = "Authorization"
+ @Deprecated(
+ message = "Please use the capitalized constant `AUTHORIZATION` instead.",
+ replaceWith = ReplaceWith("AUTHORIZATION")
+ )
+ protected const val Authorization: String = AUTHORIZATION
+
+ protected const val JSON_MEDIA_TYPE: String = "application/json"
+ @Deprecated(
+ message = "Please use the capitalized constant `JSON_MEDIA_TYPE` instead.",
+ replaceWith = ReplaceWith("JSON_MEDIA_TYPE")
+ )
+ protected const val JsonMediaType: String = JSON_MEDIA_TYPE
+
+ protected const val FORM_DATA_MEDIA_TYPE: String = "multipart/form-data"
+ @Deprecated(
+ message = "Please use the capitalized constant `FORM_DATA_MEDIA_TYPE` instead.",
+ replaceWith = ReplaceWith("FORM_DATA_MEDIA_TYPE")
+ )
+ protected const val FormDataMediaType: String = FORM_DATA_MEDIA_TYPE
+
+ protected const val FORM_URL_ENC_MEDIA_TYPE: String = "application/x-www-form-urlencoded"
+ @Deprecated(
+ message = "Please use the capitalized constant `FORM_URL_ENC_MEDIA_TYPE` instead.",
+ replaceWith = ReplaceWith("FORM_URL_ENC_MEDIA_TYPE")
+ )
+ protected const val FormUrlEncMediaType: String = FORM_URL_ENC_MEDIA_TYPE
+
+ protected const val XML_MEDIA_TYPE: String = "application/xml"
+ @Deprecated(
+ message = "Please use the capitalized constant `XML_MEDIA_TYPE` instead.",
+ replaceWith = ReplaceWith("XML_MEDIA_TYPE")
+ )
+ protected const val XmlMediaType: String = XML_MEDIA_TYPE
+
+ protected const val OCTET_MEDIA_TYPE: String = "application/octet-stream"
+ @Deprecated(
+ message = "Please use the capitalized constant `OCTET_MEDIA_TYPE` instead.",
+ replaceWith = ReplaceWith("OCTET_MEDIA_TYPE")
+ )
+ protected const val OctetMediaType: String = OCTET_MEDIA_TYPE
+
+ protected const val TEXT_MEDIA_TYPE: String = "text/plain"
+ @Deprecated(
+ message = "Please use the capitalized constant `TEXT_MEDIA_TYPE` instead.",
+ replaceWith = ReplaceWith("TEXT_MEDIA_TYPE")
+ )
+ protected const val TextMediaType: String = TEXT_MEDIA_TYPE
+
+ const val BASE_URL_KEY: String = "org.openapitools.client.baseUrl"
+ @Deprecated(
+ message = "Please use the capitalized constant `BASE_URL_KEY` instead.",
+ replaceWith = ReplaceWith("BASE_URL_KEY")
+ )
+ const val baseUrlKey: String = BASE_URL_KEY
+
+ val apiKey: MutableMap = mutableMapOf()
+ val apiKeyPrefix: MutableMap = mutableMapOf()
+ var username: String? = null
+ var password: String? = null
+ var accessToken: String? = null
+
+ @JvmStatic
+ val defaultClient: OkHttpClient by lazy {
+ builder.build()
+ }
+
+ @JvmStatic
+ val builder: OkHttpClient.Builder = OkHttpClient.Builder()
+ }
+
+ /**
+ * Guess Content-Type header from the given byteArray (defaults to "application/octet-stream").
+ *
+ * @param byteArray The given file
+ * @return The guessed Content-Type
+ */
+ protected fun guessContentTypeFromByteArray(byteArray: ByteArray): String {
+ val contentType = try {
+ URLConnection.guessContentTypeFromStream(byteArray.inputStream())
+ } catch (_: IOException) {
+ "application/octet-stream"
+ }
+ return contentType
+ }
+
+ /**
+ * Guess Content-Type header from the given file (defaults to "application/octet-stream").
+ *
+ * @param file The given file
+ * @return The guessed Content-Type
+ */
+ protected fun guessContentTypeFromFile(file: File): String {
+ val contentType = URLConnection.guessContentTypeFromName(file.name)
+ return contentType ?: "application/octet-stream"
+ }
+
+ /**
+ * Builds headers for a multipart form-data part.
+ * OkHttp requires Content-Type to be passed via the RequestBody parameter, not in headers.
+ * This function filters out Content-Type and builds the appropriate Content-Disposition header.
+ *
+ * @param name The field name
+ * @param headers The headers from the PartConfig (may include Content-Type)
+ * @param filename Optional filename for file uploads
+ * @return Headers object ready for addPart()
+ */
+ protected fun buildPartHeaders(name: String, headers: Map, filename: String? = null): Headers {
+ val disposition = if (filename != null) {
+ "form-data; name=\"$name\"; filename=\"$filename\""
+ } else {
+ "form-data; name=\"$name\""
+ }
+ return (headers.filterKeys { it != "Content-Type" } + ("Content-Disposition" to disposition)).toHeaders()
+ }
+
+ /**
+ * Adds a File to a MultipartBody.Builder
+ * Defined a helper in the requestBody method to not duplicate code
+ * It will be used when the content is a `FORM_DATA_MEDIA_TYPE` and the body of the PartConfig is a File
+ *
+ * @param name The field name to add in the request
+ * @param headers The headers that are in the PartConfig
+ * @param file The file that will be added as the field value
+ * @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
+ * @see requestBody
+ */
+ protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map, file: File) {
+ val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
+ addPart(
+ buildPartHeaders(name, headers, file.name),
+ file.asRequestBody(fileMediaType)
+ )
+ }
+
+ /**
+ * Serializes a multipart body part based on its content type.
+ * Uses JSON serialization for application/json content types, otherwise converts to string.
+ *
+ * @param obj The object to serialize
+ * @param contentType The Content-Type header value, if any
+ * @param serializer Optional custom serializer (used for kotlinx.serialization to preserve type info)
+ * @return The serialized string representation
+ */
+ protected fun serializePartBody(obj: Any?, contentType: String?, serializer: ((Any?) -> String)?): String {
+ // Use custom serializer if provided (for kotlinx.serialization with captured type info)
+ if (serializer != null) {
+ return serializer(obj)
+ }
+
+ return if (contentType?.contains("json") == true) {
+ Serializer.moshi.adapter(Any::class.java).toJson(obj)
+ } else {
+ parameterToString(obj)
+ }
+ }
+
+ /**
+ * Adds any type to a MultipartBody.Builder
+ * Defined a helper in the requestBody method to not duplicate code
+ * It will be used when the content is a `FORM_DATA_MEDIA_TYPE` and the body of the PartConfig is not a File.
+ *
+ * @param name The field name to add in the request
+ * @param headers The headers that are in the PartConfig
+ * @param obj The field name to add in the request
+ * @param serializer Optional custom serializer for this part
+ * @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
+ * @see requestBody
+ */
+ protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map, obj: Any?, serializer: ((Any?) -> String)? = null) {
+ val partContentType = headers["Content-Type"]
+ val partMediaType = partContentType?.toMediaTypeOrNull()
+ val partBody = serializePartBody(obj, partContentType, serializer)
+ addPart(
+ buildPartHeaders(name, headers),
+ partBody.toRequestBody(partMediaType)
+ )
+ }
+
+ protected inline fun requestBody(content: T, mediaType: String?): RequestBody =
+ when {
+ content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
+ content is File -> content.asRequestBody((mediaType ?: guessContentTypeFromFile(content)).toMediaTypeOrNull())
+ mediaType == FORM_DATA_MEDIA_TYPE ->
+ MultipartBody.Builder()
+ .setType(MultipartBody.FORM)
+ .apply {
+ // content's type *must* be Map>
+ @Suppress("UNCHECKED_CAST")
+ (content as Map>).forEach { (name, part) ->
+ when (part.body) {
+ is File -> addPartToMultiPart(name, part.headers, part.body)
+ is List<*> -> {
+ part.body.forEach {
+ if (it is File) {
+ addPartToMultiPart(name, part.headers, it)
+ } else {
+ addPartToMultiPart(name, part.headers, it, part.serializer)
+ }
+ }
+ }
+ else -> addPartToMultiPart(name, part.headers, part.body, part.serializer)
+ }
+ }
+ }.build()
+ mediaType == FORM_URL_ENC_MEDIA_TYPE -> {
+ FormBody.Builder().apply {
+ // content's type *must* be Map>
+ @Suppress("UNCHECKED_CAST")
+ (content as Map>).forEach { (name, part) ->
+ add(name, parameterToString(part.body))
+ }
+ }.build()
+ }
+ mediaType == null || mediaType.startsWith("application/") && mediaType.endsWith("json") ->
+ if (content == null) {
+ EMPTY_REQUEST
+ } else {
+ Serializer.moshi.adapter(T::class.java).toJson(content)
+ .toRequestBody((mediaType ?: JSON_MEDIA_TYPE).toMediaTypeOrNull())
+ }
+ mediaType == XML_MEDIA_TYPE -> throw UnsupportedOperationException("xml not currently supported.")
+ mediaType == TEXT_MEDIA_TYPE -> {
+ val textualContent = when (content) {
+ is Char, is CharSequence -> content.toString()
+ is Number -> content.toString()
+ is Boolean -> content.toString()
+ else -> throw UnsupportedOperationException("requestBody currently only supports text body containing primitive types: characters, numbers, or booleans.")
+ }
+ textualContent.toRequestBody(mediaType.toMediaTypeOrNull())
+ }
+ // TODO: this should be extended with other serializers
+ else -> throw UnsupportedOperationException("requestBody currently only supports JSON body, text body, byte body and File body.")
+ }
+
+ @OptIn(ExperimentalStdlibApi::class)
+ protected inline fun responseBody(response: Response, mediaType: String? = JSON_MEDIA_TYPE): T? {
+ val body = response.body ?: return null
+
+ if (T::class.java == Unit::class.java) {
+ // No need to parse the body when we're not interested in the body
+ // Useful when API is returning other Content-Type
+ return null
+ } else if (T::class.java == File::class.java) {
+ // return tempFile
+ val contentDisposition = response.header("Content-Disposition")
+
+ val fileName = if (contentDisposition != null) {
+ // Get filename from the Content-Disposition header.
+ val pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?")
+ val matcher = pattern.matcher(contentDisposition)
+ if (matcher.find()) {
+ matcher.group(1)
+ ?.replace(".*[/\\\\]", "")
+ ?.replace(";", "")
+ } else {
+ null
+ }
+ } else {
+ null
+ }
+
+ var prefix: String?
+ val suffix: String?
+ if (fileName == null) {
+ prefix = "download"
+ suffix = ""
+ } else {
+ val pos = fileName.lastIndexOf(".")
+ if (pos == -1) {
+ prefix = fileName
+ suffix = null
+ } else {
+ prefix = fileName.substring(0, pos)
+ suffix = fileName.substring(pos)
+ }
+ // Files.createTempFile requires the prefix to be at least three characters long
+ if (prefix.length < 3) {
+ prefix = "download"
+ }
+ }
+
+ // Attention: if you are developing an android app that supports API Level 25 and below, please check flag supportAndroidApiLevel25AndBelow in https://openapi-generator.tech/docs/generators/kotlin#config-options
+ val tempFile = java.nio.file.Files.createTempFile(prefix, suffix).toFile()
+ tempFile.deleteOnExit()
+ body.byteStream().use { inputStream ->
+ tempFile.outputStream().use { tempFileOutputStream ->
+ inputStream.copyTo(tempFileOutputStream)
+ }
+ }
+ return tempFile as T
+ }
+
+ return when {
+ mediaType == null || (mediaType.startsWith("application/") && mediaType.endsWith("json")) -> {
+ val bodyContent = body.string()
+ if (bodyContent.isEmpty()) {
+ return null
+ }
+ Serializer.moshi.adapter().fromJson(bodyContent)
+ }
+ mediaType == OCTET_MEDIA_TYPE -> body.bytes() as? T
+ mediaType == TEXT_MEDIA_TYPE -> body.string() as? T
+ else -> throw UnsupportedOperationException("responseBody currently only supports JSON body, text body and byte body.")
+ }
+ }
+
+
+ protected inline fun request(requestConfig: RequestConfig): ApiResponse {
+ val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
+
+ val url = httpUrl.newBuilder()
+ .addEncodedPathSegments(requestConfig.path.trimStart('/'))
+ .apply {
+ requestConfig.query.forEach { query ->
+ query.value.forEach { queryValue ->
+ addQueryParameter(query.key, queryValue)
+ }
+ }
+ }.build()
+
+ // take content-type/accept from spec or set to default (application/json) if not defined
+ if (requestConfig.body != null && requestConfig.headers[CONTENT_TYPE].isNullOrEmpty()) {
+ requestConfig.headers[CONTENT_TYPE] = JSON_MEDIA_TYPE
+ }
+ if (requestConfig.headers[ACCEPT].isNullOrEmpty()) {
+ requestConfig.headers[ACCEPT] = JSON_MEDIA_TYPE
+ }
+ val headers = requestConfig.headers
+
+ if (headers[ACCEPT].isNullOrEmpty()) {
+ throw kotlin.IllegalStateException("Missing ACCEPT header. This is required.")
+ }
+
+ val contentType = if (headers[CONTENT_TYPE] != null) {
+ // TODO: support multiple contentType options here.
+ (headers[CONTENT_TYPE] as String).substringBefore(";").lowercase(Locale.US)
+ } else {
+ null
+ }
+
+ val request = when (requestConfig.method) {
+ RequestMethod.DELETE -> Request.Builder().url(url).delete(requestBody(requestConfig.body, contentType))
+ RequestMethod.GET -> Request.Builder().url(url)
+ RequestMethod.HEAD -> Request.Builder().url(url).head()
+ RequestMethod.PATCH -> Request.Builder().url(url).patch(requestBody(requestConfig.body, contentType))
+ RequestMethod.PUT -> Request.Builder().url(url).put(requestBody(requestConfig.body, contentType))
+ RequestMethod.POST -> Request.Builder().url(url).post(requestBody(requestConfig.body, contentType))
+ RequestMethod.OPTIONS -> Request.Builder().url(url).method("OPTIONS", null)
+ }.apply {
+ val headersBuilder = Headers.Builder()
+ headers.forEach { header ->
+ headersBuilder.add(header.key, header.value)
+ }
+ this.headers(headersBuilder.build())
+ }.build()
+
+ val response = client.newCall(request).execute()
+
+ val accept = response.header(CONTENT_TYPE)?.substringBefore(";")?.lowercase(Locale.US)
+
+ // TODO: handle specific mapping types. e.g. Map>
+ @Suppress("UNNECESSARY_SAFE_CALL")
+ return response.use {
+ when {
+ it.isRedirect -> Redirection(
+ it.code,
+ it.headers.toMultimap()
+ )
+ it.isInformational -> Informational(
+ it.message,
+ it.code,
+ it.headers.toMultimap()
+ )
+ it.isSuccessful -> Success(
+ responseBody(it, accept),
+ it.code,
+ it.headers.toMultimap()
+ )
+ it.isClientError -> ClientError(
+ it.message,
+ it.body?.string(),
+ it.code,
+ it.headers.toMultimap()
+ )
+ else -> ServerError(
+ it.message,
+ it.body?.string(),
+ it.code,
+ it.headers.toMultimap()
+ )
+ }
+ }
+ }
+
+ protected fun parameterToString(value: Any?): String = when (value) {
+ null -> ""
+ is Array<*> -> toMultiValue(value, "csv").toString()
+ is Iterable<*> -> toMultiValue(value, "csv").toString()
+ is OffsetDateTime -> parseDateToQueryString(value)
+ is OffsetTime -> parseDateToQueryString(value)
+ is LocalDateTime -> parseDateToQueryString(value)
+ is LocalDate -> parseDateToQueryString(value)
+ is LocalTime -> parseDateToQueryString(value)
+ else -> value.toString()
+ }
+
+ protected inline fun parseDateToQueryString(value : T): String {
+ /*
+ .replace("\"", "") converts the json object string to an actual string for the query parameter.
+ The moshi or gson adapter allows a more generic solution instead of trying to use a native
+ formatter. It also easily allows to provide a simple way to define a custom date format pattern
+ inside a gson/moshi adapter.
+ */
+ return Serializer.moshi.adapter(T::class.java).toJson(value).replace("\"", "")
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt
new file mode 100644
index 000000000000..689fb03cd7ae
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt
@@ -0,0 +1,43 @@
+package org.openapitools.client.infrastructure
+
+enum class ResponseType {
+ Success, Informational, Redirection, ClientError, ServerError
+}
+
+interface Response
+
+abstract class ApiResponse(val responseType: ResponseType): Response {
+ abstract val statusCode: Int
+ abstract val headers: Map>
+}
+
+class Success(
+ val data: T,
+ override val statusCode: Int = -1,
+ override val headers: Map> = mapOf()
+): ApiResponse(ResponseType.Success)
+
+class Informational(
+ val statusText: String,
+ override val statusCode: Int = -1,
+ override val headers: Map> = mapOf()
+) : ApiResponse(ResponseType.Informational)
+
+class Redirection(
+ override val statusCode: Int = -1,
+ override val headers: Map> = mapOf()
+) : ApiResponse(ResponseType.Redirection)
+
+class ClientError(
+ val message: String? = null,
+ val body: Any? = null,
+ override val statusCode: Int = -1,
+ override val headers: Map> = mapOf()
+) : ApiResponse(ResponseType.ClientError)
+
+class ServerError(
+ val message: String? = null,
+ val body: Any? = null,
+ override val statusCode: Int = -1,
+ override val headers: Map> = mapOf()
+): ApiResponse(ResponseType.ServerError)
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt
new file mode 100644
index 000000000000..064b57fc6b82
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt
@@ -0,0 +1,17 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.math.BigDecimal
+
+class BigDecimalAdapter {
+ @ToJson
+ fun toJson(value: BigDecimal): String {
+ return value.toPlainString()
+ }
+
+ @FromJson
+ fun fromJson(value: String): BigDecimal {
+ return BigDecimal(value)
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt
new file mode 100644
index 000000000000..7df6057b4503
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt
@@ -0,0 +1,17 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.math.BigInteger
+
+class BigIntegerAdapter {
+ @ToJson
+ fun toJson(value: BigInteger): String {
+ return value.toString()
+ }
+
+ @FromJson
+ fun fromJson(value: String): BigInteger {
+ return BigInteger(value)
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt
new file mode 100644
index 000000000000..ff5e2a81ee8c
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/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-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt
new file mode 100644
index 000000000000..c83993b9055c
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt
@@ -0,0 +1,18 @@
+@file:Suppress("unused")
+package org.openapitools.client.infrastructure
+
+import java.lang.RuntimeException
+
+open class ClientException(message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) {
+
+ companion object {
+ private const val serialVersionUID: Long = 123L
+ }
+}
+
+open class ServerException(message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) {
+
+ companion object {
+ private const val serialVersionUID: Long = 456L
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt
new file mode 100644
index 000000000000..b2e1654479a0
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/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-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt
new file mode 100644
index 000000000000..e082db94811d
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/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-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt
new file mode 100644
index 000000000000..87437871a31e
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.time.OffsetDateTime
+import java.time.format.DateTimeFormatter
+
+class OffsetDateTimeAdapter {
+ @ToJson
+ fun toJson(value: OffsetDateTime): String {
+ return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value)
+ }
+
+ @FromJson
+ fun fromJson(value: String): OffsetDateTime {
+ return OffsetDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ }
+
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
new file mode 100644
index 000000000000..c2a5c99ec7e6
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Defines a config object for a given part of a multi-part request.
+ * NOTE: Headers is a Map because rfc2616 defines
+ * multi-valued headers as csv-only.
+ *
+ * @property headers The headers for this part
+ * @property body The body content for this part
+ * @property serializer Optional custom serializer for JSON content. When provided, this will be
+ * used instead of the default serialization for parts with application/json
+ * content-type. This allows capturing type information at the call site to
+ * avoid issues with type erasure in kotlinx.serialization.
+ */
+data class PartConfig(
+ val headers: MutableMap = mutableMapOf(),
+ val body: T? = null,
+ val serializer: ((Any?) -> String)? = null
+)
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
new file mode 100644
index 000000000000..6578b9381b78
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
@@ -0,0 +1,19 @@
+package org.openapitools.client.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.
+ */
+data class RequestConfig(
+ val method: RequestMethod,
+ val path: String,
+ val headers: MutableMap = mutableMapOf(),
+ val params: MutableMap = mutableMapOf(),
+ val query: MutableMap> = mutableMapOf(),
+ val requiresAuthentication: Boolean,
+ val body: T? = null
+)
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
new file mode 100644
index 000000000000..beb56f07cdde
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
@@ -0,0 +1,8 @@
+package org.openapitools.client.infrastructure
+
+/**
+ * Provides enumerated HTTP verbs
+ */
+enum class RequestMethod {
+ GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt
new file mode 100644
index 000000000000..9bd2790dc144
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt
@@ -0,0 +1,24 @@
+package org.openapitools.client.infrastructure
+
+import okhttp3.Response
+
+/**
+ * Provides an extension to evaluation whether the response is a 1xx code
+ */
+val Response.isInformational : Boolean get() = this.code in 100..199
+
+/**
+ * Provides an extension to evaluation whether the response is a 3xx code
+ */
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+val Response.isRedirect : Boolean get() = this.code in 300..399
+
+/**
+ * Provides an extension to evaluation whether the response is a 4xx code
+ */
+val Response.isClientError : Boolean get() = this.code in 400..499
+
+/**
+ * Provides an extension to evaluation whether the response is a 5xx (Standard) through 999 (non-standard) code
+ */
+val Response.isServerError : Boolean get() = this.code in 500..999
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
new file mode 100644
index 000000000000..e22592e47d74
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
@@ -0,0 +1,23 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+
+object Serializer {
+ @JvmStatic
+ val moshiBuilder: Moshi.Builder = Moshi.Builder()
+ .add(OffsetDateTimeAdapter())
+ .add(LocalDateTimeAdapter())
+ .add(LocalDateAdapter())
+ .add(UUIDAdapter())
+ .add(ByteArrayAdapter())
+ .add(URIAdapter())
+ .add(KotlinJsonAdapterFactory())
+ .add(BigDecimalAdapter())
+ .add(BigIntegerAdapter())
+
+ @JvmStatic
+ val moshi: Moshi by lazy {
+ moshiBuilder.build()
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt
new file mode 100644
index 000000000000..979301f7a030
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt
@@ -0,0 +1,13 @@
+package org.openapitools.client.infrastructure
+
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.ToJson
+import java.net.URI
+
+class URIAdapter {
+ @ToJson
+ fun toJson(uri: URI): String = uri.toString()
+
+ @FromJson
+ fun fromJson(s: String): URI = URI.create(s)
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt
new file mode 100644
index 000000000000..d050ce08f76f
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/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): String = uuid.toString()
+
+ @FromJson
+ fun fromJson(s: String): UUID = UUID.fromString(s)
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt
new file mode 100644
index 000000000000..9772cb235ae4
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/main/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModel.kt
@@ -0,0 +1,50 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.models
+
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ *
+ *
+ * @param requiredItems
+ * @param optionalItems
+ */
+
+
+data class ArrayWithNullableItemsModel (
+
+ @Json(name = "requiredItems")
+ val requiredItems: kotlin.collections.List,
+
+ @Json(name = "optionalItems")
+ val optionalItems: kotlin.collections.List? = null
+
+) {
+
+
+}
+
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt b/samples/client/petstore/kotlin-array-nullable-items/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt
new file mode 100644
index 000000000000..d2700e179dd5
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/test/kotlin/org/openapitools/client/apis/DefaultApiTest.kt
@@ -0,0 +1,45 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.apis
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+
+import org.openapitools.client.apis.DefaultApi
+import org.openapitools.client.models.ArrayWithNullableItemsModel
+
+class DefaultApiTest : ShouldSpec() {
+ init {
+ // uncomment below to create an instance of DefaultApi
+ //val apiInstance = DefaultApi()
+
+ // to test getModel
+ should("test getModel") {
+ // uncomment below to test getModel
+ //val result : ArrayWithNullableItemsModel = apiInstance.getModel()
+ //result shouldBe ("TODO")
+ }
+
+ }
+}
diff --git a/samples/client/petstore/kotlin-array-nullable-items/src/test/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModelTest.kt b/samples/client/petstore/kotlin-array-nullable-items/src/test/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModelTest.kt
new file mode 100644
index 000000000000..c99c9d5e8b92
--- /dev/null
+++ b/samples/client/petstore/kotlin-array-nullable-items/src/test/kotlin/org/openapitools/client/models/ArrayWithNullableItemsModelTest.kt
@@ -0,0 +1,49 @@
+/**
+ *
+ * Please note:
+ * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * Do not edit this file manually.
+ *
+ */
+
+@file:Suppress(
+ "ArrayInDataClass",
+ "DuplicatedCode",
+ "EnumEntryName",
+ "RemoveRedundantQualifierName",
+ "RemoveRedundantCallsOfConversionMethods",
+ "REDUNDANT_CALL_OF_CONVERSION_METHOD",
+ "RedundantUnitReturnType",
+ "RemoveEmptyClassBody",
+ "UnnecessaryVariable",
+ "UnusedImport",
+ "UnnecessaryVariable",
+ "unused"
+)
+
+package org.openapitools.client.models
+
+import io.kotlintest.shouldBe
+import io.kotlintest.specs.ShouldSpec
+
+import org.openapitools.client.models.ArrayWithNullableItemsModel
+
+class ArrayWithNullableItemsModelTest : ShouldSpec() {
+ init {
+ // uncomment below to create an instance of ArrayWithNullableItemsModel
+ //val modelInstance = ArrayWithNullableItemsModel()
+
+ // to test the property `requiredItems`
+ should("test requiredItems") {
+ // uncomment below to test the property
+ //modelInstance.requiredItems shouldBe ("TODO")
+ }
+
+ // to test the property `optionalItems`
+ should("test optionalItems") {
+ // uncomment below to test the property
+ //modelInstance.optionalItems shouldBe ("TODO")
+ }
+
+ }
+}