diff --git a/build.gradle b/build.gradle
index 7801b871..5320758e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -64,7 +64,7 @@ subprojects {
dependency 'com.samskivert:jmustache:1.12'
dependency 'commons-codec:commons-codec:1.10'
dependency 'javax.servlet:javax.servlet-api:3.1.0'
- dependency 'javax.validation:validation-api:1.1.0.Final'
+ dependency 'javax.validation:validation-api:2.0.0.Final'
dependency 'junit:junit:4.12'
dependency 'io.rest-assured:rest-assured:3.0.3'
dependency 'org.apache.pdfbox:pdfbox:2.0.7'
@@ -72,8 +72,9 @@ subprojects {
dependency 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.16'
dependency 'org.hamcrest:hamcrest-core:1.3'
dependency 'org.hamcrest:hamcrest-library:1.3'
- dependency 'org.hibernate:hibernate-validator:5.4.1.Final'
+ dependency 'org.hibernate:hibernate-validator:6.0.4.Final'
dependency 'org.jacoco:org.jacoco.agent:0.7.9'
+ dependency 'org.javamoney:moneta:1.1'
dependency 'org.jruby:jruby-complete:9.1.13.0'
dependency 'org.junit.jupiter:junit-jupiter-api:5.0.0'
dependency 'org.mockito:mockito-core:1.10.19'
diff --git a/docs/src/docs/asciidoc/documenting-your-api.adoc b/docs/src/docs/asciidoc/documenting-your-api.adoc
index b6bb3757..770af56d 100644
--- a/docs/src/docs/asciidoc/documenting-your-api.adoc
+++ b/docs/src/docs/asciidoc/documenting-your-api.adoc
@@ -1131,25 +1131,37 @@ To take complete control of constraint resolution, your own implementation of
[[documenting-your-api-constraints-describing]]
==== Describing constraints
-Default descriptions are provided for all of the Bean Validation 1.1's constraints:
+Default descriptions are provided for all of Bean Validation 2.0's constraints:
* AssertFalse
* AssertTrue
* DecimalMax
* DecimalMin
* Digits
+* Email
* Future
+* FutureOrPresent
* Max
* Min
+* Negative
+* NegativeOrZero
+* NotBlank
+* NotEmpty
* NotNull
* Null
* Past
+* PastOrPresent
* Pattern
+* Positive
+* PositiveOrZero
* Size
-Default descriptions are also provided for constraints from Hibernate Validator:
+Default descriptions are also provided for the following constraints from Hibernate
+Validator:
+* CodePointLength
* CreditCardNumber
+* Currency
* EAN
* Email
* Length
@@ -1158,6 +1170,7 @@ Default descriptions are also provided for constraints from Hibernate Validator:
* Mod11Check
* NotBlank
* NotEmpty
+* Currency
* Range
* SafeHtml
* URL
diff --git a/spring-restdocs-core/build.gradle b/spring-restdocs-core/build.gradle
index c2acd0fe..c6e7a3ca 100644
--- a/spring-restdocs-core/build.gradle
+++ b/spring-restdocs-core/build.gradle
@@ -35,6 +35,7 @@ dependencies {
optional 'junit:junit'
optional 'org.hibernate:hibernate-validator'
optional 'org.junit.jupiter:junit-jupiter-api'
+ testCompile 'org.javamoney:moneta'
testCompile 'org.mockito:mockito-core'
testCompile 'org.hamcrest:hamcrest-core'
testCompile 'org.hamcrest:hamcrest-library'
diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java
index c55596c3..9e66aa11 100644
--- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java
+++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java
@@ -25,30 +25,39 @@ import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
+import javax.validation.constraints.Email;
import javax.validation.constraints.Future;
+import javax.validation.constraints.FutureOrPresent;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
+import javax.validation.constraints.Negative;
+import javax.validation.constraints.NegativeOrZero;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Past;
+import javax.validation.constraints.PastOrPresent;
import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Positive;
+import javax.validation.constraints.PositiveOrZero;
import javax.validation.constraints.Size;
+import org.hibernate.validator.constraints.CodePointLength;
import org.hibernate.validator.constraints.CreditCardNumber;
+import org.hibernate.validator.constraints.Currency;
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.hibernate.validator.constraints.URL;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
+import org.springframework.util.StringUtils;
/**
* A {@link ConstraintDescriptionResolver} that resolves constraint descriptions from a
@@ -57,7 +66,7 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
* {@code javax.validation.constraints.NotNull} is
* {@code javax.validation.constraints.NotNull.description}.
*
- * Default descriptions are provided for Bean Validation 1.1's constraints:
+ * Default descriptions are provided for Bean Validation 2.0's constraints:
*
*
* - {@link AssertFalse}
@@ -65,13 +74,22 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
*
- {@link DecimalMax}
*
- {@link DecimalMin}
*
- {@link Digits}
+ *
- {@link Email}
*
- {@link Future}
+ *
- {@link FutureOrPresent}
*
- {@link Max}
*
- {@link Min}
+ *
- {@link Negative}
+ *
- {@link NegativeOrZero}
+ *
- {@link NotBlank}
+ *
- {@link NotEmpty}
*
- {@link NotNull}
*
- {@link Null}
*
- {@link Past}
+ *
- {@link PastOrPresent}
*
- {@link Pattern}
+ *
- {@link Positive}
+ *
- {@link PositiveOrZero}
*
- {@link Size}
*
*
@@ -79,15 +97,17 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
* Default descriptions are also provided for Hibernate Validator's constraints:
*
*
+ * - {@link CodePointLength}
*
- {@link CreditCardNumber}
+ *
- {@link Currency}
*
- {@link EAN}
- *
- {@link Email}
+ *
- {@link org.hibernate.validator.constraints.Email}
*
- {@link Length}
*
- {@link LuhnCheck}
*
- {@link Mod10Check}
*
- {@link Mod11Check}
- *
- {@link NotBlank}
- *
- {@link NotEmpty}
+ *
- {@link org.hibernate.validator.constraints.NotBlank}
+ *
- {@link org.hibernate.validator.constraints.NotEmpty}
*
- {@link Range}
*
- {@link SafeHtml}
*
- {@link URL}
@@ -169,7 +189,13 @@ public class ResourceBundleConstraintDescriptionResolver
@Override
public String resolvePlaceholder(String placeholderName) {
Object replacement = this.constraint.getConfiguration().get(placeholderName);
- return replacement != null ? replacement.toString() : null;
+ if (replacement == null) {
+ return null;
+ }
+ if (replacement.getClass().isArray()) {
+ return StringUtils.arrayToDelimitedString((Object[]) replacement, ", ");
+ }
+ return replacement.toString();
}
}
diff --git a/spring-restdocs-core/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties
index d42b5ae6..ce699e09 100644
--- a/spring-restdocs-core/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties
+++ b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties
@@ -3,15 +3,26 @@ javax.validation.constraints.AssertTrue.description=Must be true
javax.validation.constraints.DecimalMax.description=Must be at most ${value}
javax.validation.constraints.DecimalMin.description=Must be at least ${value}
javax.validation.constraints.Digits.description=Must have at most ${integer} integral digits and ${fraction} fractional digits
+javax.validation.constraints.Email.description=Must be a well-formed email address
javax.validation.constraints.Future.description=Must be in the future
+javax.validation.constraints.FutureOrPresent.description=Must be in the future or the present
javax.validation.constraints.Max.description=Must be at most ${value}
javax.validation.constraints.Min.description=Must be at least ${value}
+javax.validation.constraints.Negative.description=Must be negative
+javax.validation.constraints.NegativeOrZero.description=Must be negative or zero
+javax.validation.constraints.NotBlank.description=Must not be blank
+javax.validation.constraints.NotEmpty.description=Must not be empty
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.PastOrPresent.description=Must be in the past or the present
javax.validation.constraints.Pattern.description=Must match the regular expression `${regexp}`
+javax.validation.constraints.Positive.description=Must be positive
+javax.validation.constraints.PositiveOrZero.description=Must be positive or zero
javax.validation.constraints.Size.description=Size must be between ${min} and ${max} inclusive
+org.hibernate.validator.constraints.CodePointLength.description=Code point length 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.Currency.description=Must be in an accepted currency unit (${value})
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
diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java
index dcaa522f..95d26e91 100644
--- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java
+++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java
@@ -25,29 +25,38 @@ import java.util.List;
import java.util.ListResourceBundle;
import java.util.ResourceBundle;
+import javax.money.MonetaryAmount;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
+import javax.validation.constraints.Email;
import javax.validation.constraints.Future;
+import javax.validation.constraints.FutureOrPresent;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
+import javax.validation.constraints.Negative;
+import javax.validation.constraints.NegativeOrZero;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Past;
+import javax.validation.constraints.PastOrPresent;
import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Positive;
+import javax.validation.constraints.PositiveOrZero;
import javax.validation.constraints.Size;
+import org.hibernate.validator.constraints.CodePointLength;
import org.hibernate.validator.constraints.CreditCardNumber;
+import org.hibernate.validator.constraints.Currency;
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;
@@ -81,6 +90,18 @@ public class ResourceBundleConstraintDescriptionResolverTests {
is(equalTo("Must be true")));
}
+ @Test
+ public void defaultMessageCodePointLength() {
+ assertThat(constraintDescriptionForField("codePointLength"),
+ is(equalTo("Code point length must be between 2 and 5 inclusive")));
+ }
+
+ @Test
+ public void defaultMessageCurrency() {
+ assertThat(constraintDescriptionForField("currency"),
+ is(equalTo("Must be in an accepted currency unit (GBP, USD)")));
+ }
+
@Test
public void defaultMessageDecimalMax() {
assertThat(constraintDescriptionForField("decimalMax"),
@@ -105,6 +126,12 @@ public class ResourceBundleConstraintDescriptionResolverTests {
is(equalTo("Must be in the future")));
}
+ @Test
+ public void defaultMessageFutureOrPresent() {
+ assertThat(constraintDescriptionForField("futureOrPresent"),
+ is(equalTo("Must be in the future or the present")));
+ }
+
@Test
public void defaultMessageMax() {
assertThat(constraintDescriptionForField("max"),
@@ -134,6 +161,12 @@ public class ResourceBundleConstraintDescriptionResolverTests {
is(equalTo("Must be in the past")));
}
+ @Test
+ public void defaultMessagePastOrPresent() {
+ assertThat(constraintDescriptionForField("pastOrPresent"),
+ is(equalTo("Must be in the past or the present")));
+ }
+
@Test
public void defaultMessagePattern() {
assertThat(constraintDescriptionForField("pattern"),
@@ -164,6 +197,12 @@ public class ResourceBundleConstraintDescriptionResolverTests {
is(equalTo("Must be a well-formed email address")));
}
+ @Test
+ public void defaultMessageEmailHibernateValidator() {
+ assertThat(constraintDescriptionForField("emailHibernateValidator"),
+ is(equalTo("Must be a well-formed email address")));
+ }
+
@Test
public void defaultMessageLength() {
assertThat(constraintDescriptionForField("length"),
@@ -188,18 +227,54 @@ public class ResourceBundleConstraintDescriptionResolverTests {
is(equalTo("Must pass the Mod11 checksum algorithm")));
}
+ @Test
+ public void defaultMessageNegative() {
+ assertThat(constraintDescriptionForField("negative"),
+ is(equalTo("Must be negative")));
+ }
+
+ @Test
+ public void defaultMessageNegativeOrZero() {
+ assertThat(constraintDescriptionForField("negativeOrZero"),
+ is(equalTo("Must be negative or zero")));
+ }
+
@Test
public void defaultMessageNotBlank() {
assertThat(constraintDescriptionForField("notBlank"),
is(equalTo("Must not be blank")));
}
+ @Test
+ public void defaultMessageNotBlankHibernateValidator() {
+ assertThat(constraintDescriptionForField("notBlankHibernateValidator"),
+ is(equalTo("Must not be blank")));
+ }
+
@Test
public void defaultMessageNotEmpty() {
assertThat(constraintDescriptionForField("notEmpty"),
is(equalTo("Must not be empty")));
}
+ @Test
+ public void defaultMessageNotEmptyHibernateValidator() {
+ assertThat(constraintDescriptionForField("notEmpty"),
+ is(equalTo("Must not be empty")));
+ }
+
+ @Test
+ public void defaultMessagePositive() {
+ assertThat(constraintDescriptionForField("positive"),
+ is(equalTo("Must be positive")));
+ }
+
+ @Test
+ public void defaultMessagePositiveOrZero() {
+ assertThat(constraintDescriptionForField("positiveOrZero"),
+ is(equalTo("Must be positive or zero")));
+ }
+
@Test
public void defaultMessageRange() {
assertThat(constraintDescriptionForField("range"),
@@ -284,6 +359,12 @@ public class ResourceBundleConstraintDescriptionResolverTests {
@AssertTrue
private boolean assertTrue;
+ @CodePointLength(min = 2, max = 5)
+ private String codePointLength;
+
+ @Currency({ "GBP", "USD" })
+ private MonetaryAmount currency;
+
@DecimalMax("9.875")
private BigDecimal decimalMax;
@@ -296,6 +377,9 @@ public class ResourceBundleConstraintDescriptionResolverTests {
@Future
private Date future;
+ @FutureOrPresent
+ private Date futureOrPresent;
+
@Max(10)
private int max;
@@ -311,6 +395,9 @@ public class ResourceBundleConstraintDescriptionResolverTests {
@Past
private Date past;
+ @PastOrPresent
+ private Date pastOrPresent;
+
@Pattern(regexp = "[A-Z][a-z]+")
private String pattern;
@@ -326,6 +413,10 @@ public class ResourceBundleConstraintDescriptionResolverTests {
@Email
private String email;
+ @SuppressWarnings("deprecation")
+ @org.hibernate.validator.constraints.Email
+ private String emailHibernateValidator;
+
@Length(min = 2, max = 10)
private String length;
@@ -338,12 +429,32 @@ public class ResourceBundleConstraintDescriptionResolverTests {
@Mod11Check
private String mod11Check;
+ @Negative
+ private int negative;
+
+ @NegativeOrZero
+ private int negativeOrZero;
+
@NotBlank
private String notBlank;
+ @SuppressWarnings("deprecation")
+ @org.hibernate.validator.constraints.NotBlank
+ private String notBlankHibernateValidator;
+
@NotEmpty
private String notEmpty;
+ @SuppressWarnings("deprecation")
+ @org.hibernate.validator.constraints.NotEmpty
+ private String notEmptyHibernateValidator;
+
+ @Positive
+ private int positive;
+
+ @PositiveOrZero
+ private int positiveOrZero;
+
@Range(min = 10, max = 100)
private int range;