diff --git a/.github/workflows/samples-kotlin-server-jdk17.yaml b/.github/workflows/samples-kotlin-server-jdk17.yaml
index 32f1856207a..b66723da4b1 100644
--- a/.github/workflows/samples-kotlin-server-jdk17.yaml
+++ b/.github/workflows/samples-kotlin-server-jdk17.yaml
@@ -7,6 +7,7 @@ on:
- 'samples/server/petstore/kotlin-server/**'
- 'samples/server/petstore/kotlin-server-modelMutable/**'
- 'samples/server/petstore/kotlin-springboot-*/**'
+ - 'samples/server/petstore/kotlin-server-required-and-nullable-properties/**'
# comment out due to gradle build failure
# - samples/server/petstore/kotlin-spring-default/**
pull_request:
@@ -15,6 +16,7 @@ on:
- 'samples/server/petstore/kotlin-server/**'
- 'samples/server/petstore/kotlin-server-modelMutable/**'
- 'samples/server/petstore/kotlin-springboot-*/**'
+ - 'samples/server/petstore/kotlin-server-required-and-nullable-properties/**'
# comment out due to gradle build failure
# - samples/server/petstore/kotlin-spring-default/**
@@ -30,6 +32,7 @@ jobs:
matrix:
sample:
# server
+ - samples/server/petstore/kotlin-server-required-and-nullable-properties
- samples/server/petstore/kotlin-springboot-3
- samples/server/petstore/kotlin-springboot-delegate-nodefaults
- samples/server/petstore/kotlin-springboot-request-cookie
diff --git a/.github/workflows/samples-kotlin-server-jdk21.yaml b/.github/workflows/samples-kotlin-server-jdk21.yaml
index 18a2b82eeb9..0de80197cb7 100644
--- a/.github/workflows/samples-kotlin-server-jdk21.yaml
+++ b/.github/workflows/samples-kotlin-server-jdk21.yaml
@@ -4,9 +4,11 @@ on:
push:
paths:
- 'samples/server/petstore/kotlin-server/**'
+ - 'samples/server/petstore/kotlin-server-required-and-nullable-properties/**'
pull_request:
paths:
- 'samples/server/petstore/kotlin-server/**'
+ - 'samples/server/petstore/kotlin-server-required-and-nullable-properties/**'
env:
GRADLE_VERSION: '8.10'
@@ -21,6 +23,7 @@ jobs:
sample:
- samples/server/petstore/kotlin-server/javalin-6
- samples/server/petstore/kotlin-server/ktor
+ - samples/server/petstore/kotlin-server-required-and-nullable-properties
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
diff --git a/bin/configs/kotlin-server-required-nullable.yaml b/bin/configs/kotlin-server-required-nullable.yaml
new file mode 100644
index 00000000000..417129633a9
--- /dev/null
+++ b/bin/configs/kotlin-server-required-nullable.yaml
@@ -0,0 +1,7 @@
+generatorName: kotlin-server
+outputDir: samples/server/petstore/kotlin-server-required-and-nullable-properties
+library: javalin6
+inputSpec: modules/openapi-generator/src/test/resources/3_0/required-and-nullable-properties.yaml
+templateDir: modules/openapi-generator/src/main/resources/kotlin-server
+additionalProperties:
+ hideGenerationTimestamp: "true"
diff --git a/modules/openapi-generator/src/main/resources/kotlin-server/data_class_req_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-server/data_class_req_var.mustache
index b1c939b130b..4adcedf78cb 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-server/data_class_req_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-server/data_class_req_var.mustache
@@ -1,4 +1,5 @@
{{#description}}
/* {{{.}}} */
{{/description}}
- {{>modelMutable}} {{{name}}}: {{#isEnum}}{{{classname}}}.{{{nameInPascalCase}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}
\ No newline at end of file
+ {{! Note that required properties may be nullable according to the OpenAPI specification. }}
+ {{>modelMutable}} {{{name}}}: {{#isEnum}}{{{classname}}}.{{{nameInPascalCase}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/resources/3_0/required-and-nullable-properties.yaml b/modules/openapi-generator/src/test/resources/3_0/required-and-nullable-properties.yaml
new file mode 100644
index 00000000000..d9b9291ab35
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/required-and-nullable-properties.yaml
@@ -0,0 +1,51 @@
+# OpenAPI schemas support 4 possible combinations for properties:
+# 1. nullable + required
+# 2. nullable + not required
+# 3. not nullable + required
+# 4. not nullable + not required
+# This sample contains all of them to demonstrate how they are rendered in the generated code.
+# Related discussion: https://github.com/OpenAPITools/openapi-generator/issues/14765
+openapi: 3.0.3
+info:
+ title: Nullable Required
+ version: 1.0.0
+servers:
+ - url: /api/v3
+paths:
+ /pet:
+ post:
+ operationId: addPet
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+components:
+ schemas:
+ Pet:
+ required:
+ - notNullable_required
+ - nullable_required
+ type: object
+ properties:
+ nullable_notRequired:
+ type: string
+ example: doggie
+ nullable: true
+ notNullable_notRequired:
+ type: string
+ example: doggie
+ notNullable_required:
+ type: string
+ example: doggie
+ nullable_required:
+ type: string
+ example: doggie
+ nullable: true
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator-ignore b/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator-ignore
@@ -0,0 +1,23 @@
+# OpenAPI Generator Ignore
+# Generated by openapi-generator https://github.com/openapitools/openapi-generator
+
+# Use this file to prevent files from being overwritten by the generator.
+# The patterns follow closely to .gitignore or .dockerignore.
+
+# As an example, the C# client generator defines ApiClient.cs.
+# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
+#ApiClient.cs
+
+# You can match any string of characters against a directory, file or extension with a single asterisk (*):
+#foo/*/qux
+# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
+
+# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
+#foo/**/qux
+# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
+
+# You can also negate patterns with an exclamation (!).
+# For example, you can ignore all files in a docs folder with the file extension .md:
+#docs/*.md
+# Then explicitly reverse the ignore rule for a single file:
+#!docs/README.md
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator/FILES b/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator/FILES
new file mode 100644
index 00000000000..0ead574b64d
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator/FILES
@@ -0,0 +1,9 @@
+README.md
+build.gradle.kts
+gradle.properties
+settings.gradle
+src/main/kotlin/org/openapitools/server/Main.kt
+src/main/kotlin/org/openapitools/server/apis/DefaultApi.kt
+src/main/kotlin/org/openapitools/server/apis/DefaultApiService.kt
+src/main/kotlin/org/openapitools/server/apis/DefaultApiServiceImpl.kt
+src/main/kotlin/org/openapitools/server/models/Pet.kt
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator/VERSION b/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator/VERSION
new file mode 100644
index 00000000000..6935482704c
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/.openapi-generator/VERSION
@@ -0,0 +1 @@
+7.10.0-SNAPSHOT
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/README.md b/samples/server/petstore/kotlin-server-required-and-nullable-properties/README.md
new file mode 100644
index 00000000000..3ea7c4e8e80
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/README.md
@@ -0,0 +1,60 @@
+# org.openapitools.server - Kotlin Server library for Nullable Required
+
+No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+
+Generated by OpenAPI Generator 7.10.0-SNAPSHOT.
+
+## Build
+
+First, create the gradle wrapper script:
+
+```
+gradle wrapper
+```
+
+Then, run:
+
+```
+./gradlew check assemble
+```
+
+This runs all tests and packages the library.
+
+## Running
+
+The server builds as a fat jar with a main entrypoint. To start the service, run `java -jar ./build/libs/kotlin-server.jar`.
+
+You may also run in docker:
+
+```
+docker build -t kotlin-server .
+docker run -p 8080:8080 kotlin-server
+```
+
+## Features/Implementation Notes
+
+* Supports JSON inputs/outputs, File inputs, and Form inputs (see ktor documentation for more info).
+* ~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 */api/v3*
+
+Class | Method | HTTP request | Description
+------------ | ------------- | ------------- | -------------
+*DefaultApi* | [**addPet**](docs/DefaultApi.md#addpet) | **POST** /pet |
+
+
+
+## Documentation for Models
+
+ - [org.openapitools.server.models.Pet](docs/Pet.md)
+
+
+
+## Documentation for Authorization
+
+Endpoints do not require authorization.
+
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/build.gradle.kts b/samples/server/petstore/kotlin-server-required-and-nullable-properties/build.gradle.kts
new file mode 100644
index 00000000000..220ec0c53ac
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/build.gradle.kts
@@ -0,0 +1,33 @@
+plugins {
+ kotlin("jvm") version "2.0.21"
+}
+
+group = "org.openapitools"
+version = "1.0.0"
+
+kotlin {
+ jvmToolchain(21)
+}
+
+java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(21))
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation("io.javalin:javalin:6.1.6")
+ implementation("com.fasterxml.jackson.core:jackson-databind:2.17.1")
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.1")
+ implementation("org.slf4j:slf4j-simple:2.0.13")
+
+ testImplementation("org.jetbrains.kotlin:kotlin-test")
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/gradle.properties b/samples/server/petstore/kotlin-server-required-and-nullable-properties/gradle.properties
new file mode 100644
index 00000000000..5f1ed7bbe02
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/gradle.properties
@@ -0,0 +1 @@
+org.gradle.caching=true
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/settings.gradle b/samples/server/petstore/kotlin-server-required-and-nullable-properties/settings.gradle
new file mode 100644
index 00000000000..a09a58efab1
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'kotlin-server'
\ No newline at end of file
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/Main.kt b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/Main.kt
new file mode 100644
index 00000000000..6ad8a4dffc1
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/Main.kt
@@ -0,0 +1,21 @@
+package org.openapitools.server
+
+import io.javalin.Javalin
+import io.javalin.apibuilder.ApiBuilder.*
+
+import org.openapitools.server.apis.DefaultApi
+import org.openapitools.server.apis.DefaultApiServiceImpl
+
+fun main() {
+ val defaultApi = DefaultApi(DefaultApiServiceImpl())
+
+ val app = Javalin
+ .create { config ->
+ config.router.apiBuilder {
+ path("/pet") { post(defaultApi::addPet) }
+
+ }
+ }
+
+ app.start()
+}
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApi.kt b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApi.kt
new file mode 100644
index 00000000000..f2986b9a019
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApi.kt
@@ -0,0 +1,20 @@
+package org.openapitools.server.apis
+
+import io.javalin.http.Context
+import io.javalin.http.bodyAsClass
+import io.javalin.http.pathParamAsClass
+import io.javalin.http.queryParamAsClass
+
+import org.openapitools.server.models.Pet
+
+class DefaultApi(private val service: DefaultApiService) {
+ /**
+ *
+ * @param pet (optional)
+ */
+ fun addPet(ctx: Context) {
+ val result = service.addPet(ctx.bodyAsClass(), ctx)
+ ctx.status(200).json(result)
+ }
+
+}
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApiService.kt b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApiService.kt
new file mode 100644
index 00000000000..7d177214bfe
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApiService.kt
@@ -0,0 +1,17 @@
+package org.openapitools.server.apis
+
+import org.openapitools.server.models.Pet
+import io.javalin.http.Context
+
+interface DefaultApiService {
+
+ /**
+ * POST /pet
+ *
+ * @param pet (optional)
+ * @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
+ * @return Successful operation (status code 200)
+ * @see DefaultApi#addPet
+ */
+ fun addPet(pet: Pet?, ctx: Context): Pet
+}
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApiServiceImpl.kt b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApiServiceImpl.kt
new file mode 100644
index 00000000000..883452e3286
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/apis/DefaultApiServiceImpl.kt
@@ -0,0 +1,11 @@
+package org.openapitools.server.apis
+
+import org.openapitools.server.models.Pet
+import io.javalin.http.Context
+
+class DefaultApiServiceImpl : DefaultApiService {
+
+ override fun addPet(pet: Pet?, ctx: Context): Pet {
+ TODO("Implement me")
+ }
+}
diff --git a/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/models/Pet.kt b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/models/Pet.kt
new file mode 100644
index 00000000000..8dddb90062b
--- /dev/null
+++ b/samples/server/petstore/kotlin-server-required-and-nullable-properties/src/main/kotlin/org/openapitools/server/models/Pet.kt
@@ -0,0 +1,28 @@
+/**
+ * Nullable Required
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+*/
+package org.openapitools.server.models
+
+
+/**
+ *
+ * @param notNullableRequired
+ * @param nullableRequired
+ * @param nullableNotRequired
+ * @param notNullableNotRequired
+ */
+data class Pet(
+ val notNullableRequired: kotlin.String,
+ val nullableRequired: kotlin.String?,
+ val nullableNotRequired: kotlin.String? = null,
+ val notNullableNotRequired: kotlin.String? = null
+)
+