diff --git a/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/ConstraintResolver.kt b/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/ConstraintResolver.kt index 7dbbea13..d6176bd5 100644 --- a/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/ConstraintResolver.kt +++ b/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/ConstraintResolver.kt @@ -24,12 +24,18 @@ internal object ConstraintResolver { private const val SIZE_CONSTRAINT = "javax.validation.constraints.Size" + private const val PATTERN_CONSTRAINT = "javax.validation.constraints.Pattern" + internal fun maybeMinSizeArray(fieldDescriptor: FieldDescriptor?) = fieldDescriptor?.maybeSizeConstraint()?.let { it.configuration["min"] as? Int } internal fun maybeMaxSizeArray(fieldDescriptor: FieldDescriptor?) = fieldDescriptor?.maybeSizeConstraint()?.let { it.configuration["max"] as? Int } private fun FieldDescriptor.maybeSizeConstraint() = findConstraints(this).firstOrNull { SIZE_CONSTRAINT == it.name } + internal fun maybePattern(fieldDescriptor: FieldDescriptor?) = fieldDescriptor?.maybePatternConstraint()?.let { it.configuration["pattern"] as? String } + + private fun FieldDescriptor.maybePatternConstraint() = findConstraints(this).firstOrNull { PATTERN_CONSTRAINT == it.name } + internal fun minLengthString(fieldDescriptor: FieldDescriptor): Int? { return findConstraints(fieldDescriptor) .firstOrNull { constraint -> diff --git a/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGenerator.kt b/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGenerator.kt index 6bef678e..4d86e6ed 100644 --- a/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGenerator.kt +++ b/restdocs-api-spec-jsonschema/src/main/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGenerator.kt @@ -4,6 +4,7 @@ import com.epages.restdocs.apispec.jsonschema.ConstraintResolver.isRequired import com.epages.restdocs.apispec.jsonschema.ConstraintResolver.maxLengthString import com.epages.restdocs.apispec.jsonschema.ConstraintResolver.maybeMaxSizeArray import com.epages.restdocs.apispec.jsonschema.ConstraintResolver.maybeMinSizeArray +import com.epages.restdocs.apispec.jsonschema.ConstraintResolver.maybePattern import com.epages.restdocs.apispec.jsonschema.ConstraintResolver.minLengthString import com.epages.restdocs.apispec.model.Attributes import com.epages.restdocs.apispec.model.FieldDescriptor @@ -233,9 +234,7 @@ class JsonSchemaFromFieldDescriptorsGenerator { "array" -> ArraySchema.builder().applyConstraints(this).allItemSchema(arrayItemsSchema()) "boolean" -> BooleanSchema.builder() "number" -> NumberSchema.builder() - "string" -> StringSchema.builder() - .minLength(minLengthString(this)) - .maxLength(maxLengthString(this)) + "string" -> StringSchema.builder().applyConstraints(this) "enum" -> CombinedSchema.oneOf( listOf( StringSchema.builder().build(), @@ -282,6 +281,12 @@ class JsonSchemaFromFieldDescriptorsGenerator { } } +private fun StringSchema.Builder.applyConstraints(fieldDescriptor: FieldDescriptor) = apply { + minLength(minLengthString(fieldDescriptor)) + maxLength(maxLengthString(fieldDescriptor)) + maybePattern(fieldDescriptor)?.let { pattern(it) } +} + private fun ArraySchema.Builder.applyConstraints(fieldDescriptor: FieldDescriptor?) = apply { minItems(maybeMinSizeArray(fieldDescriptor)) maxItems(maybeMaxSizeArray(fieldDescriptor)) diff --git a/restdocs-api-spec-jsonschema/src/test/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGeneratorTest.kt b/restdocs-api-spec-jsonschema/src/test/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGeneratorTest.kt index 550cd986..83fc27ae 100644 --- a/restdocs-api-spec-jsonschema/src/test/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGeneratorTest.kt +++ b/restdocs-api-spec-jsonschema/src/test/kotlin/com/epages/restdocs/apispec/jsonschema/JsonSchemaFromFieldDescriptorsGeneratorTest.kt @@ -24,6 +24,7 @@ import org.json.JSONObject import org.junit.jupiter.api.Test import java.io.IOException import java.util.Collections.emptyMap +import java.util.regex.Pattern import javax.validation.constraints.NotNull class JsonSchemaFromFieldDescriptorsGeneratorTest { @@ -49,6 +50,12 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest { then(objectSchema.propertySchemas["id"]).isInstanceOf(StringSchema::class.java) then(objectSchema.requiredProperties).contains("id") + then(objectSchema.definesProperty("pattern")).isTrue + then(objectSchema.propertySchemas["pattern"]).isInstanceOf(StringSchema::class.java) + val patternSchema = objectSchema.propertySchemas["pattern"] as StringSchema + then(patternSchema.pattern.pattern()).isEqualTo("[a-z]") + + then(objectSchema.definesProperty("shippingAddress")).isTrue() val shippingAddressSchema = objectSchema.propertySchemas["shippingAddress"]!! then(shippingAddressSchema).isInstanceOf(ObjectSchema::class.java) @@ -116,7 +123,8 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest { "value": 1 } ] - } + }, + "pattern": "a" } """.trimIndent() ) @@ -578,6 +586,15 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest { ) ) + val patternConstraint = + Attributes( + listOf( + Constraint( + "javax.validation.constraints.Pattern", + mapOf("pattern" to "[a-z]") + ) + ) + ) fieldDescriptors = listOf( FieldDescriptor( "id", @@ -638,6 +655,12 @@ class JsonSchemaFromFieldDescriptorsGeneratorTest { ) ) ) + ), + FieldDescriptor( + "pattern", + "some", + "STRING", + attributes = patternConstraint ) ) }