Describe the bug
In Kotlin, if I have an abstract class or an interface with a nullable field, that field is not marked as nullable. Its children have that field correctly marked as nullable.
To Reproduce
- Create a Kotlin project with Spring Boot 4.1.0, springdoc-openapi-starter-webmvc-api 3.0.3, and kotlin-reflect 2.4.0
- Create an abstract class or an interface with a nullable field
- Create at least one implementation of it
- Expose it in an endpoint
plugins {
id("org.springframework.boot") version "4.1.0"
kotlin("jvm") version "2.4.0"
kotlin("plugin.spring") version "2.4.0"
}
dependencies {
implementation(platform("org.springframework.boot:spring-boot-dependencies:4.1.0"))
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.3")
implementation("org.jetbrains.kotlin:kotlin-reflect")
}
@RestController
class HelloController {
@GetMapping("/hello")
fun hello(): Shape = Circle(label = null)
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes(
JsonSubTypes.Type(value = Circle::class, name = "circle"),
JsonSubTypes.Type(value = Square::class, name = "square"),
)
abstract class Shape {
abstract val label: String?
}
data class Circle(override val label: String?) : Shape()
data class Square(override val label: String?) : Shape()
The Shape's label is "label": { "type": "string" }. Circle's is "label": { "type": ["string", "null"] }.
Expected behavior
I would expect Shape's label to be the same as Circle's: "label": { "type": ["string", "null"] }.
Additional context
Full open-api.json for the above
{
"openapi": "3.1.0",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"servers": [
{
"url": "http://localhost:8899",
"description": "Generated server url"
}
],
"paths": {
"/hello": {
"get": {
"tags": [
"hello-controller"
],
"operationId": "hello",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Circle"
},
{
"$ref": "#/components/schemas/Square"
}
]
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Circle": {
"allOf": [
{
"$ref": "#/components/schemas/Shape"
},
{
"type": "object",
"properties": {
"label": {
"type": [
"string",
"null"
]
}
}
}
]
},
"Shape": {
"type": "object",
"discriminator": {
"propertyName": "type"
},
"properties": {
"label": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"type"
]
},
"Square": {
"allOf": [
{
"$ref": "#/components/schemas/Shape"
},
{
"type": "object",
"properties": {
"label": {
"type": [
"string",
"null"
]
}
}
}
]
}
}
}
}
Describe the bug
In Kotlin, if I have an abstract class or an interface with a nullable field, that field is not marked as nullable. Its children have that field correctly marked as nullable.
To Reproduce
plugins { id("org.springframework.boot") version "4.1.0" kotlin("jvm") version "2.4.0" kotlin("plugin.spring") version "2.4.0" } dependencies { implementation(platform("org.springframework.boot:spring-boot-dependencies:4.1.0")) implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.3") implementation("org.jetbrains.kotlin:kotlin-reflect") }The Shape's label is
"label": { "type": "string" }. Circle's is"label": { "type": ["string", "null"] }.Expected behavior
I would expect Shape's label to be the same as Circle's:
"label": { "type": ["string", "null"] }.Additional context
Full open-api.json for the above
{ "openapi": "3.1.0", "info": { "title": "OpenAPI definition", "version": "v0" }, "servers": [ { "url": "http://localhost:8899", "description": "Generated server url" } ], "paths": { "/hello": { "get": { "tags": [ "hello-controller" ], "operationId": "hello", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/Circle" }, { "$ref": "#/components/schemas/Square" } ] } } } } } } } }, "components": { "schemas": { "Circle": { "allOf": [ { "$ref": "#/components/schemas/Shape" }, { "type": "object", "properties": { "label": { "type": [ "string", "null" ] } } } ] }, "Shape": { "type": "object", "discriminator": { "propertyName": "type" }, "properties": { "label": { "type": "string" }, "type": { "type": "string" } }, "required": [ "type" ] }, "Square": { "allOf": [ { "$ref": "#/components/schemas/Shape" }, { "type": "object", "properties": { "label": { "type": [ "string", "null" ] } } } ] } } } }