#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.
This commit is contained in:
@@ -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<ResolvableType, ResolvableType> DOMAIN_TYPE_CACHE = new ConcurrentReferenceHashMap<>();
|
||||
private static final Map<ResolvableType, InputPayloadMetadata> METADATA_CACHE = new ConcurrentReferenceHashMap<>();
|
||||
private static final Set<String> 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<String> getPattern() {
|
||||
|
||||
Optional<String> 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<Long> attribute = getAnnotationAttribute(RANGE_ANNOTATION, "min", Long.class);
|
||||
|
||||
if (attribute.isPresent()) {
|
||||
return attribute.get();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Long> minLong = getAnnotationAttribute(Min.class, "value", Long.class);
|
||||
|
||||
if (minLong.isPresent()) {
|
||||
return minLong.get();
|
||||
}
|
||||
|
||||
Optional<String> 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<Long> attribute = getAnnotationAttribute(RANGE_ANNOTATION, "max", Long.class);
|
||||
|
||||
if (attribute.isPresent()) {
|
||||
return attribute.get();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Long> maxLong = getAnnotationAttribute(Max.class, "value", Long.class);
|
||||
|
||||
if (maxLong.isPresent()) {
|
||||
return maxLong.get();
|
||||
}
|
||||
|
||||
Optional<String> 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<String> getDefaultPatternForNonBlank() {
|
||||
|
||||
return Optional.of(property.getAnnotation(NotBlank.class))
|
||||
.filter(MergedAnnotation::isPresent)
|
||||
.map(__ -> NOT_BLANK_REGEX);
|
||||
}
|
||||
|
||||
private Optional<Number> parsePropertyAnnotationValue(Class<? extends Annotation> type) {
|
||||
|
||||
return getAnnotationAttribute(type, "value", String.class)
|
||||
.map(BigDecimal::new);
|
||||
}
|
||||
|
||||
private String cacheAndReturn(String value) {
|
||||
|
||||
this.inputType = Optional.ofNullable(value);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user