From 80c28defba09ae1235e492a957156781aa6e90bc Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 28 Jan 2022 09:00:51 +0100 Subject: [PATCH] #1757 - Polishing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slightly more compact default regex pattern. Untangle defaulting condition in PropertyMetdata.getPattern(). Extract test cases into dedicated methods. Couple of Javadoc fixes. Java-9-based polishing by using Optional.or(…) in JSR 303 PropertyMetadata implementation. --- .../hateoas/mediatype/PropertyUtils.java | 84 +++++++------------ .../hateoas/mediatype/PropertyUtilsTest.java | 30 ++++--- 2 files changed, 47 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java b/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java index 78f65a60..9c52a053 100644 --- a/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java +++ b/src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java @@ -69,8 +69,6 @@ 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")); @@ -80,6 +78,8 @@ public class PropertyUtils { Arrays.asList(EntityModel.class, CollectionModel.class, HttpEntity.class)); private static final ResolvableType OBJECT_TYPE = ResolvableType.forClass(Object.class); + static final String NOT_BLANK_REGEX = "^(?=\\s*\\S).*$"; + static { if (ClassUtils.isPresent("org.reactivestreams.Publisher", PropertyUtils.class.getClassLoader())) { TYPES_TO_UNWRAP.addAll(ReactiveWrappers.getTypesToUnwrap()); @@ -600,7 +600,7 @@ public class PropertyUtils { /* * (non-Javadoc) - * @see org.springframework.hateoas.mediatype.PropertyUtils.PropertyMetadata#isRequired() + * @see org.springframework.hateoas.mediatype.PropertyUtils.DefaultPropertyMetadata#isRequired() */ @Override public boolean isRequired() { @@ -612,18 +612,13 @@ public class PropertyUtils { /* * (non-Javadoc) - * @see org.springframework.hateoas.mediatype.PropertyUtils.PropertyMetadata#getRegex() + * @see org.springframework.hateoas.mediatype.PropertyUtils.DefaultPropertyMetadata#getPattern() */ @Override public Optional getPattern() { - Optional attribute = getAnnotationAttribute(Pattern.class, "regexp", String.class); - - if (!attribute.isPresent() && property.getAnnotation(NotBlank.class).isPresent()) { - attribute = Optional.of(NOT_BLANK_REGEX); - } - - return attribute; + return getAnnotationAttribute(Pattern.class, "regexp", String.class) // + .or(this::getDefaultPatternForNonBlank); } /* @@ -634,28 +629,11 @@ public class PropertyUtils { @Override public Number getMin() { - if (RANGE_ANNOTATION != null) { - - Optional attribute = getAnnotationAttribute(RANGE_ANNOTATION, "min", Long.class); - - if (attribute.isPresent()) { - return attribute.get(); - } - } - - Optional minLong = getAnnotationAttribute(Min.class, "value", Long.class); - - if (minLong.isPresent()) { - return minLong.get(); - } - - Optional minDecimal = getAnnotationAttribute(DecimalMin.class, "value", String.class); - - if (minDecimal.isPresent()) { - return new BigDecimal(minDecimal.get()); - } - - return null; + return Optional.ofNullable(RANGE_ANNOTATION) // + .flatMap(it -> getAnnotationAttribute(it, "min", Number.class)) // + .or(() -> getAnnotationAttribute(Min.class, "value", Number.class)) // + .or(() -> parsePropertyAnnotationValue(DecimalMin.class)) // + .orElse(null); } /* @@ -666,28 +644,11 @@ public class PropertyUtils { @Override public Number getMax() { - if (RANGE_ANNOTATION != null) { - - Optional attribute = getAnnotationAttribute(RANGE_ANNOTATION, "max", Long.class); - - if (attribute.isPresent()) { - return attribute.get(); - } - } - - Optional maxLong = getAnnotationAttribute(Max.class, "value", Long.class); - - if (maxLong.isPresent()) { - return maxLong.get(); - } - - Optional maxDecimal = getAnnotationAttribute(DecimalMax.class, "value", String.class); - - if (maxDecimal.isPresent()) { - return new BigDecimal(maxDecimal.get()); - } - - return null; + return Optional.ofNullable(RANGE_ANNOTATION) // + .flatMap(it -> getAnnotationAttribute(it, "max", Number.class)) // + .or(() -> getAnnotationAttribute(Max.class, "value", Number.class)) // + .or(() -> parsePropertyAnnotationValue(DecimalMax.class)) // + .orElse(null); } /* @@ -737,6 +698,19 @@ public class PropertyUtils { return cacheAndReturn(inputType != null ? inputType : super.getInputType()); } + private Optional getDefaultPatternForNonBlank() { + + return Optional.of(property.getAnnotation(NotBlank.class)) + .filter(MergedAnnotation::isPresent) + .map(__ -> NOT_BLANK_REGEX); + } + + private Optional parsePropertyAnnotationValue(Class type) { + + return getAnnotationAttribute(type, "value", String.class) + .map(BigDecimal::new); + } + private String cacheAndReturn(String value) { this.inputType = Optional.ofNullable(value); diff --git a/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java b/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java index d0c15942..011dd40b 100644 --- a/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java +++ b/src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java @@ -151,7 +151,7 @@ class PropertyUtilsTest { } @Test - void considersJsr303Annotations() { + void considersBasicJsr303Annotations() { InputPayloadMetadata metadata = PropertyUtils.getExposedProperties(Jsr303SamplePayload.class); @@ -159,20 +159,10 @@ 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"); }); @@ -219,6 +209,22 @@ class PropertyUtilsTest { .isThrownBy(() -> PropertyUtils.getExposedProperties(TypeWithRecordStyleAccessors.class)); } + @Test // #1753 + void considersJsr303NotBlankAnnotation() { + + InputPayloadMetadata metadata = PropertyUtils.getExposedProperties(Jsr303SamplePayload.class); + + assertThat(getProperty(metadata, "nonBlank")).hasValueSatisfying(it -> { + assertThat(it.isRequired()).isTrue(); + assertThat(it.getPattern()).hasValue(PropertyUtils.NOT_BLANK_REGEX); + }); + + assertThat(getProperty(metadata, "nonBlankPattern")).hasValueSatisfying(it -> { + assertThat(it.isRequired()).isTrue(); + assertThat(it.getPattern()).hasValue("\\w"); + }); + } + @Data @AllArgsConstructor @JsonIgnoreProperties({ "ignoreThisProperty" }) @@ -263,7 +269,7 @@ class PropertyUtilsTest { @NotNull String nonNull; @NotBlank String nonBlank; @Pattern(regexp = "\\w") String pattern; - @NotBlank @Pattern(regexp = "\\w") String nonBlankPattern; + @NotBlank @Pattern(regexp = "\\w") String nonBlankPattern; TypeAnnotated annotated; }