Skip to content

Commit

Permalink
Feat : apply optional is nullable (#245)
Browse files Browse the repository at this point in the history
* feat: apply optional is nullable

* chore: refactoring

* chore: remove needless

* fix deprecated

* fix for test
  • Loading branch information
xeromank authored Sep 4, 2023
1 parent 4c735ca commit 2900374
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.everit.json.schema.ArraySchema
import org.everit.json.schema.BooleanSchema
import org.everit.json.schema.CombinedSchema
import org.everit.json.schema.CombinedSchema.oneOf
import org.everit.json.schema.EmptySchema
import org.everit.json.schema.EnumSchema
import org.everit.json.schema.NullSchema
Expand Down Expand Up @@ -206,9 +207,26 @@ class JsonSchemaFromFieldDescriptorsGenerator {
) : FieldDescriptor(path, description, type, optional, ignored, attributes) {

fun jsonSchemaType(): Schema {
val schemaBuilders = jsonSchemaPrimitiveTypes.map { typeToSchema(it) }
return if (schemaBuilders.size == 1) schemaBuilders.first().description(description).build()
else CombinedSchema.oneOf(schemaBuilders.map { it.build() }).description(description).build()
val schemaBuilders: List<Schema.Builder<*>>
if (jsonSchemaPrimitiveTypes.size > 1 &&
optional &&
!jsonSchemaPrimitiveTypes.contains("null")
) {
schemaBuilders = jsonSchemaPrimitiveTypes
.plus(jsonSchemaPrimitiveTypeFromDescriptorType("null"))
.map { typeToSchema(it) }
} else {
schemaBuilders = jsonSchemaPrimitiveTypes.map { typeToSchema(it) }
}
return if (schemaBuilders.size == 1) schemaBuilders.first().description(description).checkNullable().build()
else oneOf(schemaBuilders.map { it.build() }).description(description).checkNullable().build()
}

private fun Schema.Builder<out Schema>.checkNullable(): Schema.Builder<out Schema> {
if (optional) {
this.nullable(true)
}
return this
}

fun merge(fieldDescriptor: FieldDescriptor): FieldDescriptorWithSchemaType {
Expand All @@ -230,7 +248,9 @@ class JsonSchemaFromFieldDescriptorsGenerator {

private fun typeToSchema(type: String): Schema.Builder<*> =
when (type) {
"null" -> NullSchema.builder()
"null" -> {
NullSchema.builder().nullable()
}
"empty" -> EmptySchema.builder()
"object" -> ObjectSchema.builder()
"array" -> ArraySchema.builder().applyConstraints(this).allItemSchema(arrayItemsSchema())
Expand All @@ -246,9 +266,14 @@ class JsonSchemaFromFieldDescriptorsGenerator {
else -> throw IllegalArgumentException("unknown field type $type")
}

private fun NullSchema.Builder.nullable(): NullSchema.Builder {
this.nullable(true)
return this
}

private fun arrayItemsSchema(): Schema {
return attributes.itemsType
?.let { typeToSchema(it.toLowerCase()).build() }
?.let { typeToSchema(it.lowercase()).build() }
?: CombinedSchema.oneOf(
listOf(
ObjectSchema.builder().build(),
Expand Down Expand Up @@ -277,7 +302,7 @@ class JsonSchemaFromFieldDescriptorsGenerator {
)

private fun jsonSchemaPrimitiveTypeFromDescriptorType(fieldDescriptorType: String) =
fieldDescriptorType.toLowerCase()
fieldDescriptorType.lowercase()
.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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.everit.json.schema.Schema
import org.everit.json.schema.StringSchema
import org.everit.json.schema.ValidationException
import org.everit.json.schema.loader.SchemaLoader
import org.everit.json.schema.loader.internal.DefaultSchemaClient
import org.json.JSONArray
import org.json.JSONObject
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -61,6 +62,7 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest {
val shippingAddressSchema = objectSchema.propertySchemas["shippingAddress"]!!
then(shippingAddressSchema).isInstanceOf(ObjectSchema::class.java)
then(shippingAddressSchema.description).isNotEmpty()
then(shippingAddressSchema.isNullable).isTrue()

then(objectSchema.definesProperty("billingAddress")).isTrue()
val billingAddressSchema = objectSchema.propertySchemas["billingAddress"] as ObjectSchema
Expand Down Expand Up @@ -120,6 +122,7 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest {
then(pagePositiveSchema.minimum.toInt()).isEqualTo(1)
then(pagePositiveSchema.maximum).isNull()
then(pagePositiveSchema.requiresInteger()).isTrue
then(pagePositiveSchema.isNullable).isTrue()

then(objectSchema.definesProperty("page100_200")).isTrue
then(objectSchema.propertySchemas["page100_200"]).isInstanceOf(NumberSchema::class.java)
Expand Down Expand Up @@ -445,7 +448,14 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest {
private fun whenSchemaGenerated() {
schemaString = generator.generateSchema(fieldDescriptors!!)
println(schemaString)
schema = SchemaLoader.load(JSONObject(schemaString))
schema = SchemaLoader
.builder()
.nullableSupport(true)
.schemaJson(JSONObject(schemaString))
.schemaClient(DefaultSchemaClient())
.build()
.load()
.build()
}

private fun givenFieldDescriptorWithPrimitiveArray() {
Expand Down Expand Up @@ -589,9 +599,9 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest {

private fun givenDifferentFieldDescriptorsWithSamePathAndDifferentTypes() {
fieldDescriptors = listOf(
FieldDescriptor("id", "some", "STRING"),
FieldDescriptor("id", "some", "NULL"),
FieldDescriptor("id", "some", "BOOLEAN")
FieldDescriptor("id", "some", "STRING", true),
FieldDescriptor("id", "some", "NULL", true),
FieldDescriptor("id", "some", "BOOLEAN", true)
)
}

Expand Down

0 comments on commit 2900374

Please sign in to comment.