@@ -15,6 +15,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
1515import org.everit.json.schema.ArraySchema
1616import org.everit.json.schema.BooleanSchema
1717import org.everit.json.schema.CombinedSchema
18+ import org.everit.json.schema.CombinedSchema.oneOf
1819import org.everit.json.schema.EmptySchema
1920import org.everit.json.schema.EnumSchema
2021import org.everit.json.schema.NullSchema
@@ -206,9 +207,26 @@ class JsonSchemaFromFieldDescriptorsGenerator {
206207 ) : FieldDescriptor(path, description, type, optional, ignored, attributes) {
207208
208209 fun jsonSchemaType (): Schema {
209- val schemaBuilders = jsonSchemaPrimitiveTypes.map { typeToSchema(it) }
210- return if (schemaBuilders.size == 1 ) schemaBuilders.first().description(description).build()
211- else CombinedSchema .oneOf(schemaBuilders.map { it.build() }).description(description).build()
210+ val schemaBuilders: List <Schema .Builder <* >>
211+ if (jsonSchemaPrimitiveTypes.size > 1 &&
212+ optional &&
213+ ! jsonSchemaPrimitiveTypes.contains(" null" )
214+ ) {
215+ schemaBuilders = jsonSchemaPrimitiveTypes
216+ .plus(jsonSchemaPrimitiveTypeFromDescriptorType(" null" ))
217+ .map { typeToSchema(it) }
218+ } else {
219+ schemaBuilders = jsonSchemaPrimitiveTypes.map { typeToSchema(it) }
220+ }
221+ return if (schemaBuilders.size == 1 ) schemaBuilders.first().description(description).checkNullable().build()
222+ else oneOf(schemaBuilders.map { it.build() }).description(description).checkNullable().build()
223+ }
224+
225+ private fun Schema.Builder <out Schema >.checkNullable (): Schema .Builder <out Schema > {
226+ if (optional) {
227+ this .nullable(true )
228+ }
229+ return this
212230 }
213231
214232 fun merge (fieldDescriptor : FieldDescriptor ): FieldDescriptorWithSchemaType {
@@ -230,7 +248,9 @@ class JsonSchemaFromFieldDescriptorsGenerator {
230248
231249 private fun typeToSchema (type : String ): Schema .Builder <* > =
232250 when (type) {
233- " null" -> NullSchema .builder()
251+ " null" -> {
252+ NullSchema .builder().nullable()
253+ }
234254 " empty" -> EmptySchema .builder()
235255 " object" -> ObjectSchema .builder()
236256 " array" -> ArraySchema .builder().applyConstraints(this ).allItemSchema(arrayItemsSchema())
@@ -246,9 +266,14 @@ class JsonSchemaFromFieldDescriptorsGenerator {
246266 else -> throw IllegalArgumentException (" unknown field type $type " )
247267 }
248268
269+ private fun NullSchema.Builder.nullable (): NullSchema .Builder {
270+ this .nullable(true )
271+ return this
272+ }
273+
249274 private fun arrayItemsSchema (): Schema {
250275 return attributes.itemsType
251- ?.let { typeToSchema(it.toLowerCase ()).build() }
276+ ?.let { typeToSchema(it.lowercase ()).build() }
252277 ? : CombinedSchema .oneOf(
253278 listOf (
254279 ObjectSchema .builder().build(),
@@ -277,7 +302,7 @@ class JsonSchemaFromFieldDescriptorsGenerator {
277302 )
278303
279304 private fun jsonSchemaPrimitiveTypeFromDescriptorType (fieldDescriptorType : String ) =
280- fieldDescriptorType.toLowerCase ()
305+ fieldDescriptorType.lowercase ()
281306 .let { if (it == " varies" ) " empty" else it } // varies is used by spring rest docs if the type is ambiguous - in json schema we want to represent as empty
282307 }
283308 }
0 commit comments