From 31585c7f385347e542e85240170f069232a49ecf Mon Sep 17 00:00:00 2001 From: thowimmer Date: Fri, 22 Nov 2019 15:19:52 +0100 Subject: [PATCH 1/3] Add support for constraints on nested fields. --- .../restdocs/apispec/ConstrainedFields.kt | 5 ++++- .../restdocs/apispec/ConstrainedFieldsTest.kt | 20 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt b/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt index f0518daf..05881de4 100644 --- a/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt +++ b/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt @@ -18,7 +18,7 @@ class ConstrainedFields(private val classHoldingConstraints: Class<*>) { * @param path json path of the field */ fun withPath(path: String): FieldDescriptor = - withMappedPath(path, path) + withMappedPath(path, beanPropertyNameFromPath(path)) /** * @@ -38,7 +38,10 @@ class ConstrainedFields(private val classHoldingConstraints: Class<*>) { .value(this.validatorConstraintResolver.resolveForProperty(beanPropertyName, classHoldingConstraints)) ) + private fun beanPropertyNameFromPath(jsonPath: String) = jsonPath.substringAfter(DOT_NOTATION_DELIMITER) + companion object { private const val CONSTRAINTS_KEY = "validationConstraints" + private const val DOT_NOTATION_DELIMITER = "." } } diff --git a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt index 4a9a25f0..a6d559a2 100644 --- a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt +++ b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt @@ -7,11 +7,11 @@ import javax.validation.constraints.NotEmpty internal class ConstrainedFieldsTest { - val fields = ConstrainedFields(SomeWithConstraints::class.java) @Test @Suppress("UNCHECKED_CAST") fun `should resolve constraints`() { + val fields = ConstrainedFields(SomeWithConstraints::class.java) val descriptor = fields.withPath("nonEmpty") then(descriptor.attributes).containsKey("validationConstraints") @@ -19,7 +19,25 @@ internal class ConstrainedFieldsTest { .containsExactly(NotEmpty::class.java.name) } + @Test + @Suppress("UNCHECKED_CAST") + fun `should resolve nested constraints`() { + val fields = ConstrainedFields(SomeOtherWithConstraints::class.java) + val descriptor = fields.withPath("nested.nonEmpty") + + then(descriptor.attributes).containsKey("validationConstraints") + then((descriptor.attributes["validationConstraints"] as List).map { it.name }) + .containsExactly(NotEmpty::class.java.name) + } + private data class SomeWithConstraints( + @field:NotEmpty + val nonEmpty: String, + + val nested: SomeOtherWithConstraints + ) + + private data class SomeOtherWithConstraints( @field:NotEmpty val nonEmpty: String ) From 85d6ae4311a47f4d1601e60c4dbdf7d8cdc62ef1 Mon Sep 17 00:00:00 2001 From: thowimmer Date: Fri, 22 Nov 2019 15:38:39 +0100 Subject: [PATCH 2/3] Removed needless blank lines in ConstrainedFieldsTest. --- .../kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt index a6d559a2..e75df56d 100644 --- a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt +++ b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt @@ -7,7 +7,6 @@ import javax.validation.constraints.NotEmpty internal class ConstrainedFieldsTest { - @Test @Suppress("UNCHECKED_CAST") fun `should resolve constraints`() { From 2dee63d681fc5fc4f015b508285606a0f71f370e Mon Sep 17 00:00:00 2001 From: thowimmer Date: Fri, 22 Nov 2019 19:05:42 +0100 Subject: [PATCH 3/3] Fixed that constraint nesting is only working for one level of nesting. --- .../restdocs/apispec/ConstrainedFields.kt | 2 +- .../restdocs/apispec/ConstrainedFieldsTest.kt | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt b/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt index 05881de4..224932c4 100644 --- a/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt +++ b/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/ConstrainedFields.kt @@ -38,7 +38,7 @@ class ConstrainedFields(private val classHoldingConstraints: Class<*>) { .value(this.validatorConstraintResolver.resolveForProperty(beanPropertyName, classHoldingConstraints)) ) - private fun beanPropertyNameFromPath(jsonPath: String) = jsonPath.substringAfter(DOT_NOTATION_DELIMITER) + private fun beanPropertyNameFromPath(jsonPath: String) = jsonPath.substringAfterLast(DOT_NOTATION_DELIMITER) companion object { private const val CONSTRAINTS_KEY = "validationConstraints" diff --git a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt index e75df56d..00f3ca09 100644 --- a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt +++ b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/ConstrainedFieldsTest.kt @@ -20,8 +20,8 @@ internal class ConstrainedFieldsTest { @Test @Suppress("UNCHECKED_CAST") - fun `should resolve nested constraints`() { - val fields = ConstrainedFields(SomeOtherWithConstraints::class.java) + fun `should resolve one level nested constraints`() { + val fields = ConstrainedFields(SomeWithConstraints::class.java) val descriptor = fields.withPath("nested.nonEmpty") then(descriptor.attributes).containsKey("validationConstraints") @@ -29,15 +29,21 @@ internal class ConstrainedFieldsTest { .containsExactly(NotEmpty::class.java.name) } + @Test + @Suppress("UNCHECKED_CAST") + fun `should resolve two level nested constraints`() { + val fields = ConstrainedFields(SomeWithConstraints::class.java) + val descriptor = fields.withPath("nested.nested.nonEmpty") + + then(descriptor.attributes).containsKey("validationConstraints") + then((descriptor.attributes["validationConstraints"] as List).map { it.name }) + .containsExactly(NotEmpty::class.java.name) + } + private data class SomeWithConstraints( @field:NotEmpty val nonEmpty: String, - val nested: SomeOtherWithConstraints - ) - - private data class SomeOtherWithConstraints( - @field:NotEmpty - val nonEmpty: String + val nested: SomeWithConstraints? ) }