Skip to content
This repository was archived by the owner on Mar 16, 2025. It is now read-only.

Commit 6eb20fb

Browse files
committed
#45, wrap "nullable" object properties
1 parent 9f6d19a commit 6eb20fb

File tree

3 files changed

+134
-3
lines changed

3 files changed

+134
-3
lines changed

src/main/kotlin/io/openapiprocessor/core/converter/DataTypeConverter.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.openapiprocessor.core.converter
77

88
import io.openapiprocessor.core.converter.mapping.*
9+
import io.openapiprocessor.core.converter.wrapper.NullDataTypeWrapper
910
import io.openapiprocessor.core.model.DataTypeCollector
1011
import io.openapiprocessor.core.model.DataTypes
1112
import io.openapiprocessor.core.model.datatypes.*
@@ -17,7 +18,8 @@ import kotlin.collections.LinkedHashMap
1718
*/
1819
class DataTypeConverter(
1920
private val options: ApiOptions,
20-
private val finder: MappingFinder = MappingFinder(options.typeMappings)
21+
private val finder: MappingFinder = MappingFinder(options.typeMappings),
22+
private val nullWrapper: NullDataTypeWrapper = NullDataTypeWrapper(options, finder)
2123
) {
2224
private val current: Deque<SchemaInfo> = LinkedList()
2325

@@ -142,7 +144,6 @@ class DataTypeConverter(
142144
constraints,
143145
schemaInfo.getDeprecated()
144146
)
145-
return mappedDataType
146147
}
147148

148149
return ArrayDataType(item, constraints, schemaInfo.getDeprecated())
@@ -155,7 +156,12 @@ class DataTypeConverter(
155156
private fun createObjectDataType(schemaInfo: SchemaInfo, dataTypes: DataTypes): DataType {
156157
val properties = LinkedHashMap<String, DataType>()
157158
schemaInfo.eachProperty { propName: String, propSchemaInfo: SchemaInfo ->
158-
properties[propName] = convert(propSchemaInfo, dataTypes)
159+
var propDataType = convert(propSchemaInfo, dataTypes)
160+
161+
if (propSchemaInfo.getNullable()) {
162+
propDataType = nullWrapper.wrap(propDataType, schemaInfo)
163+
}
164+
properties[propName] = propDataType
159165
}
160166

161167
val targetType = getMappedDataType(schemaInfo)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright © 2020 https://github.com/openapi-processor/openapi-processor-core
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.core.converter
7+
8+
import io.kotest.core.spec.style.StringSpec
9+
import io.kotest.matchers.shouldBe
10+
import io.kotest.matchers.types.shouldBeInstanceOf
11+
import io.openapiprocessor.core.converter.mapping.EndpointTypeMapping
12+
import io.openapiprocessor.core.converter.mapping.TypeMapping
13+
import io.openapiprocessor.core.model.DataTypes
14+
import io.openapiprocessor.core.model.HttpMethod
15+
import io.openapiprocessor.core.model.datatypes.ObjectDataType
16+
import io.openapiprocessor.core.support.getBodySchemaInfo
17+
import io.openapiprocessor.core.support.parse
18+
19+
class DataTypeConverterNullSpec: StringSpec({
20+
21+
val dataTypes = DataTypes()
22+
23+
"wraps object property in a null wrapper if a null mappings exists" {
24+
val openApi = parse("""
25+
openapi: 3.0.2
26+
info:
27+
title: API
28+
version: 1.0.0
29+
30+
paths:
31+
/foo:
32+
patch:
33+
requestBody:
34+
content:
35+
application/json:
36+
schema:
37+
${'$'}ref: '#/components/schemas/Foo'
38+
responses:
39+
'204':
40+
description: empty
41+
42+
components:
43+
schemas:
44+
45+
Foo:
46+
description: a Foo
47+
type: object
48+
properties:
49+
foo:
50+
nullable: true
51+
type: string
52+
53+
""".trimIndent())
54+
55+
56+
val options = ApiOptions()
57+
options.typeMappings = listOf(
58+
EndpointTypeMapping("/foo", listOf(
59+
TypeMapping(
60+
"null",
61+
"org.openapitools.jackson.nullable.JsonNullable"
62+
)))
63+
)
64+
65+
val schemaInfo = openApi.getBodySchemaInfo("Foo",
66+
"/foo", HttpMethod.PATCH, "application/json")
67+
68+
// when:
69+
val converter = DataTypeConverter(options)
70+
val datatype = converter.convert(schemaInfo, dataTypes)
71+
72+
// then:
73+
datatype.shouldBeInstanceOf<ObjectDataType>()
74+
val fooDataType = datatype.getObjectProperty("foo")
75+
fooDataType.getName().shouldBe("JsonNullable<String>")
76+
}
77+
78+
})

src/test/kotlin/io/openapiprocessor/core/support/OpenApiSchema.kt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,37 @@ fun OpenApi.getSchema(path: String, method: HttpMethod, status: String, mediaTyp
4343
return media?.getSchema()!!
4444
}
4545

46+
/**
47+
* extracts a specific request body Schema from an [OpenApi] object created by [parse()][parse].
48+
*
49+
* @param path the endpoint path
50+
* @param method the http method
51+
* @return the [Schema]
52+
*/
53+
fun OpenApi.getBodySchema(path: String, method: HttpMethod, mediaType: String): Schema {
54+
val endpoint = this.getPaths()[path]
55+
if (endpoint == null) {
56+
println("unknown path '$path' !")
57+
}
58+
59+
val operation = endpoint?.getOperations()?.find { it.getMethod() == method }
60+
if (operation == null) {
61+
println("unknown method '$method' ($path)!")
62+
}
63+
64+
val body = operation?.getRequestBody()
65+
if (body == null) {
66+
println("no body ($path $method)!")
67+
}
68+
69+
val media = body?.getContent()?.get(mediaType)
70+
if (media == null) {
71+
println("unknown media type '$mediaType' ($path $method)!")
72+
}
73+
74+
return media?.getSchema()!!
75+
}
76+
4677
/**
4778
* extracts a specific response Schema from an [OpenApi] object created by [parse()][parse] and
4879
* creates a [SchemaInfo] for the schema.
@@ -58,3 +89,19 @@ fun OpenApi.getSchemaInfo(name: String, path: String, method: HttpMethod, status
5889
val schema = getSchema(path, method, status, mediaType)
5990
return SchemaInfo(path, name, mediaType, schema, getRefResolver())
6091
}
92+
93+
/**
94+
* extracts a specific body Schema from an [OpenApi] object created by [parse()][parse] and
95+
* creates a [SchemaInfo] for the schema.
96+
*
97+
* @param name name of schema info, i.e the datatype name
98+
* @param path the endpoint path
99+
* @param method the http method
100+
* @return the [SchemaInfo]
101+
*/
102+
fun OpenApi.getBodySchemaInfo(name: String, path: String, method: HttpMethod, mediaType: String)
103+
: SchemaInfo {
104+
val schema = getBodySchema(path, method, mediaType)
105+
return SchemaInfo(path, path.substring(1).capitalize() + "RequestBody",
106+
mediaType, schema, getRefResolver())
107+
}

0 commit comments

Comments
 (0)