From 1f6f1e24d4c3f4eba63d42bf798dd2f7397febe7 Mon Sep 17 00:00:00 2001 From: Faron Dutton Date: Tue, 18 Jan 2022 12:36:26 -0500 Subject: [PATCH] #1757 - Add support for javax.validation.constraints.NotBlank. The presence of @NonBlank on a representation model's property now causes it to be considered required. It will also cause a default pattern exposed that allows clients to validate input values. Fixes #1757. --- .../hateoas/mediatype/PropertyUtils.java | 17 +++++++++++++++-- .../hateoas/mediatype/PropertyUtilsTest.java | 13 +++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java b/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java index 17799eeb..78f65a60 100644 --- a/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java +++ b/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java @@ -31,6 +31,7 @@ import javax.validation.constraints.DecimalMin; import javax.validation.constraints.Email; import javax.validation.constraints.Max; import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @@ -68,6 +69,8 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped; */ public class PropertyUtils { + static final String NOT_BLANK_REGEX = "^\\s*(\\S+\\s*)+$"; + private static final Map DOMAIN_TYPE_CACHE = new ConcurrentReferenceHashMap<>(); private static final Map METADATA_CACHE = new ConcurrentReferenceHashMap<>(); private static final Set FIELDS_TO_IGNORE = new HashSet<>(Arrays.asList("class", "links")); @@ -601,7 +604,10 @@ public class PropertyUtils { */ @Override public boolean isRequired() { - return super.isRequired() || property.getAnnotation(NotNull.class).isPresent(); + + return super.isRequired() // + || property.getAnnotation(NotNull.class).isPresent() // + || property.getAnnotation(NotBlank.class).isPresent(); } /* @@ -610,7 +616,14 @@ public class PropertyUtils { */ @Override public Optional getPattern() { - return getAnnotationAttribute(Pattern.class, "regexp", String.class); + + Optional attribute = getAnnotationAttribute(Pattern.class, "regexp", String.class); + + if (!attribute.isPresent() && property.getAnnotation(NotBlank.class).isPresent()) { + attribute = Optional.of(NOT_BLANK_REGEX); + } + + return attribute; } /* diff --git a/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java b/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java index bfafc434..d0c15942 100644 --- a/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java +++ b/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java @@ -31,6 +31,7 @@ import java.util.Optional; import java.util.stream.Stream; import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @@ -158,10 +159,20 @@ class PropertyUtilsTest { assertThat(it.isRequired()).isTrue(); }); + assertThat(getProperty(metadata, "nonBlank")).hasValueSatisfying(it -> { + assertThat(it.isRequired()).isTrue(); + assertThat(it.getPattern()).hasValue(PropertyUtils.NOT_BLANK_REGEX); + }); + assertThat(getProperty(metadata, "pattern")).hasValueSatisfying(it -> { assertThat(it.getPattern()).hasValue("\\w"); }); + assertThat(getProperty(metadata, "nonBlankPattern")).hasValueSatisfying(it -> { + assertThat(it.isRequired()).isTrue(); + assertThat(it.getPattern()).hasValue("\\w"); + }); + assertThat(getProperty(metadata, "annotated")).hasValueSatisfying(it -> { assertThat(it.getPattern()).hasValue("regex"); }); @@ -250,7 +261,9 @@ class PropertyUtilsTest { static class Jsr303SamplePayload { @NotNull String nonNull; + @NotBlank String nonBlank; @Pattern(regexp = "\\w") String pattern; + @NotBlank @Pattern(regexp = "\\w") String nonBlankPattern; TypeAnnotated annotated; }