Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,15 @@ class KotlinNullablePropertyCustomizer(
* Marks a non-$ref property as nullable.
* - OAS 3.0: `nullable: true`
* - OAS 3.1: adds `"null"` to the `types` set
*
* A schema representing `Any?` carries no `type`/`types` constraint, i.e. it is an
* "any" schema which already permits any value including `null`. Such a schema is left
* untouched (kept as an empty schema) rather than being narrowed to `type: "null"`
* (3.1) or decorated with a redundant `nullable: true` (3.0).
*/
private fun markNullable(property: Schema<*>, specVersion: SpecVersion) {
if (isAnySchema(property)) return

if (specVersion == SpecVersion.V31) {
val currentTypes = property.types ?: property.type?.let { setOf(it) } ?: emptySet()
if ("null" !in currentTypes) {
Expand All @@ -140,6 +147,16 @@ class KotlinNullablePropertyCustomizer(
}
}

/**
* Returns true when the schema imposes no type constraint (i.e. represents `Any`),
* in which case it is treated as an empty schema that already allows any value,
* including `null`.
*/
private fun isAnySchema(property: Schema<*>): Boolean =
property.`$ref` == null &&
property.type == null &&
property.types.isNullOrEmpty()

/**
* Wraps a $ref property in a nullable composite schema. A fresh wrapper schema is returned
* (the original property object is left untouched) with any sibling attributes such as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ data class NullableFieldsResponse(
val requiredField: String,
val nullableString: String? = null,
val nullableInt: Int? = null,
val nullableAny: Any? = null,
@field:Schema(description = "The nested object")
val nullableNested: NestedObject? = null,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ data class NullableFieldsResponse(
val requiredField: String,
val nullableString: String? = null,
val nullableInt: Int? = null,
val nullableAny: Any? = null,
val nullableNested: NestedObject? = null,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ data class NullableFieldsResponse(
val requiredField: String,
val nullableString: String? = null,
val nullableInt: Int? = null,
val nullableAny: Any? = null,
@field:Schema(description = "The nested object")
val nullableNested: NestedObject? = null,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ data class NullableFieldsResponse(
val requiredField: String,
val nullableString: String? = null,
val nullableInt: Int? = null,
val nullableAny: Any? = null,
val nullableNested: NestedObject? = null,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
"format": "int32",
"nullable": true
},
"nullableAny" : {
"type" : "object",
"nullable" : true
},
"nullableNested": {
"nullable": true,
"allOf": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
"type": "integer",
"format": "int32"
},
"nullableAny" : {
"type" : "object"
},
"nullableNested": {
"$ref": "#/components/schemas/NestedObject"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
],
"format": "int32"
},
"nullableAny": { },
"nullableNested": {
"description": "The nested object",
"oneOf": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"type": "integer",
"format": "int32"
},
"nullableAny": { },
"nullableNested": {
"$ref": "#/components/schemas/NestedObject"
}
Expand Down
Loading