Skip to content

Commit f867e90

Browse files
author
Andrei Badea
committed
Add mechanism to disable nullable for Kotlin properties
1 parent da4cb67 commit f867e90

8 files changed

Lines changed: 255 additions & 0 deletions

File tree

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocKotlinConfiguration.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class SpringDocKotlinConfiguration() {
8181
@Bean
8282
@Lazy(false)
8383
@ConditionalOnMissingBean
84+
@ConditionalOnProperty(name = [Constants.SPRINGDOC_KOTLIN_NULLABLE_PROPERTY_CUSTOMIZER_ENABLED], matchIfMissing = true)
8485
fun kotlinNullablePropertyCustomizer(objectMapperProvider: ObjectMapperProvider): KotlinNullablePropertyCustomizer {
8586
return KotlinNullablePropertyCustomizer(objectMapperProvider)
8687
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ public final class Constants {
106106
*/
107107
public static final String SPRINGDOC_POLYMORPHIC_CONVERTER_ENABLED = "springdoc.model-converters.polymorphic-converter.enabled";
108108

109+
/**
110+
* The constant SPRINGDOC_KOTLIN_NULLABLE_PROPERTY_CUSTOMIZER_ENABLED.
111+
*/
112+
public static final String SPRINGDOC_KOTLIN_NULLABLE_PROPERTY_CUSTOMIZER_ENABLED = "springdoc.model-converters.kotlin-nullable-property-customizer.enabled";
113+
109114
/**
110115
* The constant SPRINGDOC_SCHEMA_RESOLVE_PROPERTIES.
111116
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package test.org.springdoc.api.v30.app19
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
data class NullableFieldsResponse(
7+
val requiredField: String,
8+
val nullableString: String? = null,
9+
val nullableInt: Int? = null,
10+
val nullableNested: NestedObject? = null,
11+
)
12+
13+
data class NestedObject(
14+
val name: String,
15+
val description: String? = null,
16+
)
17+
18+
@RestController
19+
class NullableController {
20+
@GetMapping("/nullable")
21+
fun getNullableFields(): NullableFieldsResponse = NullableFieldsResponse(requiredField = "hello")
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package test.org.springdoc.api.v30.app19
2+
3+
import io.swagger.v3.core.converter.ModelConverters
4+
import org.springdoc.core.customizers.KotlinNullablePropertyCustomizer
5+
import org.springdoc.core.utils.Constants
6+
import org.springframework.boot.autoconfigure.SpringBootApplication
7+
import org.springframework.context.annotation.ComponentScan
8+
import org.springframework.test.context.TestPropertySource
9+
import test.org.springdoc.api.v30.AbstractKotlinSpringDocMVCTest
10+
11+
@TestPropertySource(
12+
properties = [
13+
"springdoc.api-docs.version=openapi_3_0", Constants.SPRINGDOC_KOTLIN_NULLABLE_PROPERTY_CUSTOMIZER_ENABLED +
14+
"=false",
15+
],
16+
)
17+
class SpringDocApp19Test : AbstractKotlinSpringDocMVCTest() {
18+
companion object {
19+
init {
20+
ModelConverters
21+
.getInstance(false)
22+
.getConverters()
23+
.filterIsInstance<KotlinNullablePropertyCustomizer>()
24+
.forEach { ModelConverters.getInstance(false).removeConverter(it) }
25+
}
26+
}
27+
28+
@SpringBootApplication
29+
@ComponentScan(basePackages = ["org.springdoc", "test.org.springdoc.api.v30.app19"])
30+
class DemoApplication
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package test.org.springdoc.api.v31.app24
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
data class NullableFieldsResponse(
7+
val requiredField: String,
8+
val nullableString: String? = null,
9+
val nullableInt: Int? = null,
10+
val nullableNested: NestedObject? = null,
11+
)
12+
13+
data class NestedObject(
14+
val name: String,
15+
val description: String? = null,
16+
)
17+
18+
@RestController
19+
class NullableController {
20+
@GetMapping("/nullable")
21+
fun getNullableFields(): NullableFieldsResponse = NullableFieldsResponse(requiredField = "hello")
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package test.org.springdoc.api.v31.app24
2+
3+
import io.swagger.v3.core.converter.ModelConverters
4+
import org.springdoc.core.customizers.KotlinNullablePropertyCustomizer
5+
import org.springdoc.core.utils.Constants
6+
import org.springframework.boot.autoconfigure.SpringBootApplication
7+
import org.springframework.context.annotation.ComponentScan
8+
import org.springframework.test.context.TestPropertySource
9+
import test.org.springdoc.api.v31.AbstractKotlinSpringDocMVCTest
10+
11+
@TestPropertySource(properties = [Constants.SPRINGDOC_KOTLIN_NULLABLE_PROPERTY_CUSTOMIZER_ENABLED + "=false"])
12+
class SpringDocApp24Test : AbstractKotlinSpringDocMVCTest() {
13+
companion object {
14+
init {
15+
ModelConverters
16+
.getInstance(true)
17+
.getConverters()
18+
.filterIsInstance<KotlinNullablePropertyCustomizer>()
19+
.forEach { ModelConverters.getInstance(true).removeConverter(it) }
20+
}
21+
}
22+
23+
@SpringBootApplication
24+
@ComponentScan(basePackages = ["org.springdoc", "test.org.springdoc.api.v31.app24"])
25+
class DemoApplication
26+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/nullable": {
15+
"get": {
16+
"tags": [
17+
"nullable-controller"
18+
],
19+
"operationId": "getNullableFields",
20+
"responses": {
21+
"200": {
22+
"description": "OK",
23+
"content": {
24+
"*/*": {
25+
"schema": {
26+
"$ref": "#/components/schemas/NullableFieldsResponse"
27+
}
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
},
35+
"components": {
36+
"schemas": {
37+
"NestedObject": {
38+
"required": [
39+
"name"
40+
],
41+
"type": "object",
42+
"properties": {
43+
"name": {
44+
"type": "string"
45+
},
46+
"description": {
47+
"type": "string"
48+
}
49+
}
50+
},
51+
"NullableFieldsResponse": {
52+
"required": [
53+
"requiredField"
54+
],
55+
"type": "object",
56+
"properties": {
57+
"requiredField": {
58+
"type": "string"
59+
},
60+
"nullableString": {
61+
"type": "string"
62+
},
63+
"nullableInt": {
64+
"type": "integer",
65+
"format": "int32"
66+
},
67+
"nullableNested": {
68+
"$ref": "#/components/schemas/NestedObject"
69+
}
70+
}
71+
}
72+
}
73+
}
74+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"openapi": "3.1.0",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/nullable": {
15+
"get": {
16+
"tags": [
17+
"nullable-controller"
18+
],
19+
"operationId": "getNullableFields",
20+
"responses": {
21+
"200": {
22+
"description": "OK",
23+
"content": {
24+
"*/*": {
25+
"schema": {
26+
"$ref": "#/components/schemas/NullableFieldsResponse"
27+
}
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
},
35+
"components": {
36+
"schemas": {
37+
"NestedObject": {
38+
"type": "object",
39+
"properties": {
40+
"name": {
41+
"type": "string"
42+
},
43+
"description": {
44+
"type": "string"
45+
}
46+
},
47+
"required": [
48+
"name"
49+
]
50+
},
51+
"NullableFieldsResponse": {
52+
"type": "object",
53+
"properties": {
54+
"requiredField": {
55+
"type": "string"
56+
},
57+
"nullableString": {
58+
"type": "string"
59+
},
60+
"nullableInt": {
61+
"type": "integer",
62+
"format": "int32"
63+
},
64+
"nullableNested": {
65+
"$ref": "#/components/schemas/NestedObject"
66+
}
67+
},
68+
"required": [
69+
"requiredField"
70+
]
71+
}
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)