Add default descriptions for Hibernate Validator's constraints

Closes gh-151
This commit is contained in:
Andy Wilkinson
2016-04-13 12:00:56 +01:00
parent e5aa5ba728
commit ecdc1971c2
3 changed files with 233 additions and 59 deletions

View File

@@ -534,6 +534,21 @@ Default descriptions are provided for all of the Bean Validation 1.1's constrain
* Pattern
* Size
Default descriptions are also provided for constraints from Hibernate Validator:
* CreditCardNumber
* EAN
* Email
* Length
* LuhnCheck
* Mod10Check
* Mod11Check
* NotBlank
* NotEmpty
* Range
* SafeHtml
* URL
To override the default descriptions, or to provide a new description, create a resource
bundle with the base name
`org.springframework.restdocs.constraints.ConstraintDescriptions`. The Spring

View File

@@ -10,4 +10,16 @@ javax.validation.constraints.NotNull.description=Must not be null
javax.validation.constraints.Null.description=Must be null
javax.validation.constraints.Past.description=Must be in the past
javax.validation.constraints.Pattern.description=Must match the regular expression '${regexp}'
javax.validation.constraints.Size.description=Size must be between ${min} and ${max} inclusive
javax.validation.constraints.Size.description=Size must be between ${min} and ${max} inclusive
org.hibernate.validator.constraints.CreditCardNumber.description=Must be a well-formed credit card number
org.hibernate.validator.constraints.EAN.description=Must be a well-formed ${type} number
org.hibernate.validator.constraints.Email.description=Must be a well-formed email address
org.hibernate.validator.constraints.Length.description=Length must be between ${min} and ${max} inclusive
org.hibernate.validator.constraints.LuhnCheck.description=Must pass the Luhn Modulo 10 checksum algorithm
org.hibernate.validator.constraints.Mod10Check.description=Must pass the Mod10 checksum algorithm
org.hibernate.validator.constraints.Mod11Check.description=Must pass the Mod11 checksum algorithm
org.hibernate.validator.constraints.NotBlank.description=Must not be blank
org.hibernate.validator.constraints.NotEmpty.description=Must not be empty
org.hibernate.validator.constraints.Range.description=Must be at least ${min} and at most ${max}
org.hibernate.validator.constraints.SafeHtml.description=Must be safe HTML
org.hibernate.validator.constraints.URL.description=Must be a well-formed URL

View File

@@ -16,11 +16,13 @@
package org.springframework.restdocs.constraints;
import java.lang.annotation.Annotation;
import java.math.BigDecimal;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Date;
import java.util.List;
import java.util.ListResourceBundle;
import java.util.Map;
import java.util.ResourceBundle;
import javax.validation.constraints.AssertFalse;
@@ -37,8 +39,23 @@ import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.CreditCardNumber;
import org.hibernate.validator.constraints.EAN;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.LuhnCheck;
import org.hibernate.validator.constraints.Mod10Check;
import org.hibernate.validator.constraints.Mod11Check;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.SafeHtml;
import org.junit.Test;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -54,111 +71,151 @@ public class ResourceBundleConstraintDescriptionResolverTests {
@Test
public void defaultMessageAssertFalse() {
String description = this.resolver.resolveDescription(new Constraint(
AssertFalse.class.getName(), Collections.<String, Object>emptyMap()));
assertThat(description, is(equalTo("Must be false")));
assertThat(constraintDescriptionForField("assertFalse"),
is(equalTo("Must be false")));
}
@Test
public void defaultMessageAssertTrue() {
String description = this.resolver.resolveDescription(new Constraint(
AssertTrue.class.getName(), Collections.<String, Object>emptyMap()));
assertThat(description, is(equalTo("Must be true")));
assertThat(constraintDescriptionForField("assertTrue"),
is(equalTo("Must be true")));
}
@Test
public void defaultMessageDecimalMax() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("value", "9.875");
String description = this.resolver.resolveDescription(
new Constraint(DecimalMax.class.getName(), configuration));
assertThat(description, is(equalTo("Must be at most 9.875")));
assertThat(constraintDescriptionForField("decimalMax"),
is(equalTo("Must be at most 9.875")));
}
@Test
public void defaultMessageDecimalMin() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("value", "1.5");
String description = this.resolver.resolveDescription(
new Constraint(DecimalMin.class.getName(), configuration));
assertThat(description, is(equalTo("Must be at least 1.5")));
assertThat(constraintDescriptionForField("decimalMin"),
is(equalTo("Must be at least 1.5")));
}
@Test
public void defaultMessageDigits() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("integer", "2");
configuration.put("fraction", "5");
String description = this.resolver.resolveDescription(
new Constraint(Digits.class.getName(), configuration));
assertThat(description, is(equalTo(
"Must have at most 2 integral digits and 5 " + "fractional digits")));
assertThat(constraintDescriptionForField("digits"), is(
equalTo("Must have at most 2 integral digits and 5 fractional digits")));
}
@Test
public void defaultMessageFuture() {
String description = this.resolver.resolveDescription(new Constraint(
Future.class.getName(), Collections.<String, Object>emptyMap()));
assertThat(description, is(equalTo("Must be in the future")));
assertThat(constraintDescriptionForField("future"),
is(equalTo("Must be in the future")));
}
@Test
public void defaultMessageMax() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("value", 10);
String description = this.resolver
.resolveDescription(new Constraint(Max.class.getName(), configuration));
assertThat(description, is(equalTo("Must be at most 10")));
assertThat(constraintDescriptionForField("max"),
is(equalTo("Must be at most 10")));
}
@Test
public void defaultMessageMin() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("value", 10);
String description = this.resolver
.resolveDescription(new Constraint(Min.class.getName(), configuration));
assertThat(description, is(equalTo("Must be at least 10")));
assertThat(constraintDescriptionForField("min"),
is(equalTo("Must be at least 10")));
}
@Test
public void defaultMessageNotNull() {
String description = this.resolver.resolveDescription(new Constraint(
NotNull.class.getName(), Collections.<String, Object>emptyMap()));
assertThat(description, is(equalTo("Must not be null")));
assertThat(constraintDescriptionForField("notNull"),
is(equalTo("Must not be null")));
}
@Test
public void defaultMessageNull() {
String description = this.resolver.resolveDescription(new Constraint(
Null.class.getName(), Collections.<String, Object>emptyMap()));
assertThat(description, is(equalTo("Must be null")));
assertThat(constraintDescriptionForField("nul"), is(equalTo("Must be null")));
}
@Test
public void defaultMessagePast() {
String description = this.resolver.resolveDescription(new Constraint(
Past.class.getName(), Collections.<String, Object>emptyMap()));
assertThat(description, is(equalTo("Must be in the past")));
assertThat(constraintDescriptionForField("past"),
is(equalTo("Must be in the past")));
}
@Test
public void defaultMessagePattern() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("regexp", "[A-Z][a-z]+");
String description = this.resolver.resolveDescription(
new Constraint(Pattern.class.getName(), configuration));
assertThat(description,
assertThat(constraintDescriptionForField("pattern"),
is(equalTo("Must match the regular expression '[A-Z][a-z]+'")));
}
@Test
public void defaultMessageSize() {
Map<String, Object> configuration = new HashMap<>();
configuration.put("min", 2);
configuration.put("max", 10);
String description = this.resolver
.resolveDescription(new Constraint(Size.class.getName(), configuration));
assertThat(description, is(equalTo("Size must be between 2 and 10 inclusive")));
assertThat(constraintDescriptionForField("size"),
is(equalTo("Size must be between 2 and 10 inclusive")));
}
@Test
public void defaultMessageCreditCardNumber() {
assertThat(constraintDescriptionForField("creditCardNumber"),
is(equalTo("Must be a well-formed credit card number")));
}
@Test
public void defaultMessageEan() {
assertThat(constraintDescriptionForField("ean"),
is(equalTo("Must be a well-formed EAN13 number")));
}
@Test
public void defaultMessageEmail() {
assertThat(constraintDescriptionForField("email"),
is(equalTo("Must be a well-formed email address")));
}
@Test
public void defaultMessageLength() {
assertThat(constraintDescriptionForField("length"),
is(equalTo("Length must be between 2 and 10 inclusive")));
}
@Test
public void defaultMessageLuhnCheck() {
assertThat(constraintDescriptionForField("luhnCheck"),
is(equalTo("Must pass the Luhn Modulo 10 checksum algorithm")));
}
@Test
public void defaultMessageMod10Check() {
assertThat(constraintDescriptionForField("mod10Check"),
is(equalTo("Must pass the Mod10 checksum algorithm")));
}
@Test
public void defaultMessageMod11Check() {
assertThat(constraintDescriptionForField("mod11Check"),
is(equalTo("Must pass the Mod11 checksum algorithm")));
}
@Test
public void defaultMessageNotBlank() {
assertThat(constraintDescriptionForField("notBlank"),
is(equalTo("Must not be blank")));
}
@Test
public void defaultMessageNotEmpty() {
assertThat(constraintDescriptionForField("notEmpty"),
is(equalTo("Must not be empty")));
}
@Test
public void defaultMessageRange() {
assertThat(constraintDescriptionForField("range"),
is(equalTo("Must be at least 10 and at most 100")));
}
@Test
public void defaultMessageSafeHtml() {
assertThat(constraintDescriptionForField("safeHtml"),
is(equalTo("Must be safe HTML")));
}
@Test
public void defaultMessageUrl() {
assertThat(constraintDescriptionForField("url"),
is(equalTo("Must be a well-formed URL")));
}
@Test
@@ -206,4 +263,94 @@ public class ResourceBundleConstraintDescriptionResolverTests {
assertThat(description, is(equalTo("Not null")));
}
private String constraintDescriptionForField(String name) {
return this.resolver.resolveDescription(getConstraintFromField(name));
}
private Constraint getConstraintFromField(String name) {
Annotation[] annotations = ReflectionUtils.findField(Constrained.class, name)
.getAnnotations();
Assert.isTrue(annotations.length == 1);
return new Constraint(annotations[0].annotationType().getName(),
AnnotationUtils.getAnnotationAttributes(annotations[0]));
}
private static class Constrained {
@AssertFalse
private boolean assertFalse;
@AssertTrue
private boolean assertTrue;
@DecimalMax("9.875")
private BigDecimal decimalMax;
@DecimalMin("1.5")
private BigDecimal decimalMin;
@Digits(integer = 2, fraction = 5)
private String digits;
@Future
private Date future;
@Max(10)
private int max;
@Min(10)
private int min;
@NotNull
private String notNull;
@Null
private String nul;
@Past
private Date past;
@Pattern(regexp = "[A-Z][a-z]+")
private String pattern;
@Size(min = 2, max = 10)
private List<String> size;
@CreditCardNumber
private String creditCardNumber;
@EAN
private String ean;
@Email
private String email;
@Length(min = 2, max = 10)
private String length;
@LuhnCheck
private String luhnCheck;
@Mod10Check
private String mod10Check;
@Mod11Check
private String mod11Check;
@NotBlank
private String notBlank;
@NotEmpty
private String notEmpty;
@Range(min = 10, max = 100)
private int range;
@SafeHtml
private String safeHtml;
@org.hibernate.validator.constraints.URL
private String url;
}
}