Skip to content

Commit 80c28de

Browse files
committed
#1757 - Polishing.
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.
1 parent 1f6f1e2 commit 80c28de

File tree

2 files changed

+47
-67
lines changed

2 files changed

+47
-67
lines changed

src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java

Lines changed: 29 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@
6969
*/
7070
public class PropertyUtils {
7171

72-
static final String NOT_BLANK_REGEX = "^\\s*(\\S+\\s*)+$";
73-
7472
private static final Map<ResolvableType, ResolvableType> DOMAIN_TYPE_CACHE = new ConcurrentReferenceHashMap<>();
7573
private static final Map<ResolvableType, InputPayloadMetadata> METADATA_CACHE = new ConcurrentReferenceHashMap<>();
7674
private static final Set<String> FIELDS_TO_IGNORE = new HashSet<>(Arrays.asList("class", "links"));
@@ -80,6 +78,8 @@ public class PropertyUtils {
8078
Arrays.asList(EntityModel.class, CollectionModel.class, HttpEntity.class));
8179
private static final ResolvableType OBJECT_TYPE = ResolvableType.forClass(Object.class);
8280

81+
static final String NOT_BLANK_REGEX = "^(?=\\s*\\S).*$";
82+
8383
static {
8484
if (ClassUtils.isPresent("org.reactivestreams.Publisher", PropertyUtils.class.getClassLoader())) {
8585
TYPES_TO_UNWRAP.addAll(ReactiveWrappers.getTypesToUnwrap());
@@ -600,7 +600,7 @@ private Jsr303AwarePropertyMetadata(AnnotatedProperty property) {
600600

601601
/*
602602
* (non-Javadoc)
603-
* @see org.springframework.hateoas.mediatype.PropertyUtils.PropertyMetadata#isRequired()
603+
* @see org.springframework.hateoas.mediatype.PropertyUtils.DefaultPropertyMetadata#isRequired()
604604
*/
605605
@Override
606606
public boolean isRequired() {
@@ -612,18 +612,13 @@ public boolean isRequired() {
612612

613613
/*
614614
* (non-Javadoc)
615-
* @see org.springframework.hateoas.mediatype.PropertyUtils.PropertyMetadata#getRegex()
615+
* @see org.springframework.hateoas.mediatype.PropertyUtils.DefaultPropertyMetadata#getPattern()
616616
*/
617617
@Override
618618
public Optional<String> getPattern() {
619619

620-
Optional<String> attribute = getAnnotationAttribute(Pattern.class, "regexp", String.class);
621-
622-
if (!attribute.isPresent() && property.getAnnotation(NotBlank.class).isPresent()) {
623-
attribute = Optional.of(NOT_BLANK_REGEX);
624-
}
625-
626-
return attribute;
620+
return getAnnotationAttribute(Pattern.class, "regexp", String.class) //
621+
.or(this::getDefaultPatternForNonBlank);
627622
}
628623

629624
/*
@@ -634,28 +629,11 @@ public Optional<String> getPattern() {
634629
@Override
635630
public Number getMin() {
636631

637-
if (RANGE_ANNOTATION != null) {
638-
639-
Optional<Long> attribute = getAnnotationAttribute(RANGE_ANNOTATION, "min", Long.class);
640-
641-
if (attribute.isPresent()) {
642-
return attribute.get();
643-
}
644-
}
645-
646-
Optional<Long> minLong = getAnnotationAttribute(Min.class, "value", Long.class);
647-
648-
if (minLong.isPresent()) {
649-
return minLong.get();
650-
}
651-
652-
Optional<String> minDecimal = getAnnotationAttribute(DecimalMin.class, "value", String.class);
653-
654-
if (minDecimal.isPresent()) {
655-
return new BigDecimal(minDecimal.get());
656-
}
657-
658-
return null;
632+
return Optional.ofNullable(RANGE_ANNOTATION) //
633+
.flatMap(it -> getAnnotationAttribute(it, "min", Number.class)) //
634+
.or(() -> getAnnotationAttribute(Min.class, "value", Number.class)) //
635+
.or(() -> parsePropertyAnnotationValue(DecimalMin.class)) //
636+
.orElse(null);
659637
}
660638

661639
/*
@@ -666,28 +644,11 @@ public Number getMin() {
666644
@Override
667645
public Number getMax() {
668646

669-
if (RANGE_ANNOTATION != null) {
670-
671-
Optional<Long> attribute = getAnnotationAttribute(RANGE_ANNOTATION, "max", Long.class);
672-
673-
if (attribute.isPresent()) {
674-
return attribute.get();
675-
}
676-
}
677-
678-
Optional<Long> maxLong = getAnnotationAttribute(Max.class, "value", Long.class);
679-
680-
if (maxLong.isPresent()) {
681-
return maxLong.get();
682-
}
683-
684-
Optional<String> maxDecimal = getAnnotationAttribute(DecimalMax.class, "value", String.class);
685-
686-
if (maxDecimal.isPresent()) {
687-
return new BigDecimal(maxDecimal.get());
688-
}
689-
690-
return null;
647+
return Optional.ofNullable(RANGE_ANNOTATION) //
648+
.flatMap(it -> getAnnotationAttribute(it, "max", Number.class)) //
649+
.or(() -> getAnnotationAttribute(Max.class, "value", Number.class)) //
650+
.or(() -> parsePropertyAnnotationValue(DecimalMax.class)) //
651+
.orElse(null);
691652
}
692653

693654
/*
@@ -737,6 +698,19 @@ public String getInputType() {
737698
return cacheAndReturn(inputType != null ? inputType : super.getInputType());
738699
}
739700

701+
private Optional<String> getDefaultPatternForNonBlank() {
702+
703+
return Optional.of(property.getAnnotation(NotBlank.class))
704+
.filter(MergedAnnotation::isPresent)
705+
.map(__ -> NOT_BLANK_REGEX);
706+
}
707+
708+
private Optional<Number> parsePropertyAnnotationValue(Class<? extends Annotation> type) {
709+
710+
return getAnnotationAttribute(type, "value", String.class)
711+
.map(BigDecimal::new);
712+
}
713+
740714
private String cacheAndReturn(String value) {
741715

742716
this.inputType = Optional.ofNullable(value);

src/test/java/org/springframework/hateoas/mediatype/PropertyUtilsTest.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,28 +151,18 @@ void considersAccessorAvailablility() {
151151
}
152152

153153
@Test
154-
void considersJsr303Annotations() {
154+
void considersBasicJsr303Annotations() {
155155

156156
InputPayloadMetadata metadata = PropertyUtils.getExposedProperties(Jsr303SamplePayload.class);
157157

158158
assertThat(getProperty(metadata, "nonNull")).hasValueSatisfying(it -> {
159159
assertThat(it.isRequired()).isTrue();
160160
});
161161

162-
assertThat(getProperty(metadata, "nonBlank")).hasValueSatisfying(it -> {
163-
assertThat(it.isRequired()).isTrue();
164-
assertThat(it.getPattern()).hasValue(PropertyUtils.NOT_BLANK_REGEX);
165-
});
166-
167162
assertThat(getProperty(metadata, "pattern")).hasValueSatisfying(it -> {
168163
assertThat(it.getPattern()).hasValue("\\w");
169164
});
170165

171-
assertThat(getProperty(metadata, "nonBlankPattern")).hasValueSatisfying(it -> {
172-
assertThat(it.isRequired()).isTrue();
173-
assertThat(it.getPattern()).hasValue("\\w");
174-
});
175-
176166
assertThat(getProperty(metadata, "annotated")).hasValueSatisfying(it -> {
177167
assertThat(it.getPattern()).hasValue("regex");
178168
});
@@ -219,6 +209,22 @@ void detectesPropertiesWithRecordStyleAccessorsCorrectly() {
219209
.isThrownBy(() -> PropertyUtils.getExposedProperties(TypeWithRecordStyleAccessors.class));
220210
}
221211

212+
@Test // #1753
213+
void considersJsr303NotBlankAnnotation() {
214+
215+
InputPayloadMetadata metadata = PropertyUtils.getExposedProperties(Jsr303SamplePayload.class);
216+
217+
assertThat(getProperty(metadata, "nonBlank")).hasValueSatisfying(it -> {
218+
assertThat(it.isRequired()).isTrue();
219+
assertThat(it.getPattern()).hasValue(PropertyUtils.NOT_BLANK_REGEX);
220+
});
221+
222+
assertThat(getProperty(metadata, "nonBlankPattern")).hasValueSatisfying(it -> {
223+
assertThat(it.isRequired()).isTrue();
224+
assertThat(it.getPattern()).hasValue("\\w");
225+
});
226+
}
227+
222228
@Data
223229
@AllArgsConstructor
224230
@JsonIgnoreProperties({ "ignoreThisProperty" })
@@ -263,7 +269,7 @@ static class Jsr303SamplePayload {
263269
@NotNull String nonNull;
264270
@NotBlank String nonBlank;
265271
@Pattern(regexp = "\\w") String pattern;
266-
@NotBlank @Pattern(regexp = "\\w") String nonBlankPattern;
272+
@NotBlank @Pattern(regexp = "\\w") String nonBlankPattern;
267273
TypeAnnotated annotated;
268274
}
269275

0 commit comments

Comments
 (0)