From 4d97a05fbca0bd1cd146b5cebd43544dcda1e7c0 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 24 May 2019 23:31:06 +0200 Subject: [PATCH 1/2] SpringValidatorAdapter applies MessageFormat to {0}-containing message Closes gh-23014 --- .../SpringValidatorAdapter.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java index ce974b975f..a55fff3d69 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java @@ -169,7 +169,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. errors.getObjectName(), errorCodes, errorArgs, violation.getMessage()) { @Override public boolean shouldRenderDefaultMessage() { - return false; + return requiresMessageFormat(violation); } }; error.wrap(violation); @@ -182,7 +182,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. rejectedValue, false, errorCodes, errorArgs, violation.getMessage()) { @Override public boolean shouldRenderDefaultMessage() { - return false; + return requiresMessageFormat(violation); } }; error.wrap(violation); @@ -300,12 +300,36 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. * @param field the field that caused the binding error * @return a corresponding {@code MessageSourceResolvable} for the specified field * @since 4.3 + * @see #getArgumentsForConstraint */ protected MessageSourceResolvable getResolvableField(String objectName, String field) { String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field}; return new DefaultMessageSourceResolvable(codes, field); } + /** + * Indicate whether this violation's interpolated message has remaining + * placeholders and therefore requires {@link java.text.MessageFormat} + * to be applied to it. Called for a Bean Validation defined message + * (coming out {@code ValidationMessages.properties}) when rendered + * as the default message in Spring's MessageSource. + *

The default implementation considers a Spring-style "{0}" placeholder + * for the field name as an indication for {@link java.text.MessageFormat}. + * Any other placeholder or escape syntax occurrences are typically a + * mismatch, coming out of regex pattern values or the like. Note that + * standard Bean Validation does not support "{0}" style placeholders at all; + * this is a feature typically used in Spring MessageSource resource bundles. + * @param violation the Bean Validation constraint violation, including + * BV-defined interpolation of named attribute references in its message + * @return {@code true} if {@code java.text.MessageFormat} is to be applied, + * or {@code false} if the violation's message should be used as-is + * @since 5.1.8 + * @see #getArgumentsForConstraint + */ + protected boolean requiresMessageFormat(ConstraintViolation violation) { + return violation.getMessage().contains("{0}"); + } + /** * Extract the rejected value behind the given constraint violation, * for exposure through the Spring errors representation. From 80c6f2bcf9146d3f6fb6fbe593b22e78d2e570ca Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 24 May 2019 23:31:32 +0200 Subject: [PATCH 2/2] Polishing --- .../beanvalidation2/SpringValidatorAdapterTests.java | 4 ++-- .../beanvalidation/SpringValidatorAdapterTests.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java b/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java index 192b1d99d5..e488036d40 100644 --- a/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java +++ b/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java @@ -75,7 +75,7 @@ public class SpringValidatorAdapterTests { @Before public void setupSpringValidatorAdapter() { - messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} is must be between {2} and {1}"); + messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} must be between {2} and {1}"); messageSource.addMessage("Same", Locale.ENGLISH, "{2} must be same value as {1}"); messageSource.addMessage("password", Locale.ENGLISH, "Password"); messageSource.addMessage("confirmPassword", Locale.ENGLISH, "Password(Confirm)"); @@ -101,7 +101,7 @@ public class SpringValidatorAdapterTests { assertThat(errors.getFieldValue("password"), is("pass")); FieldError error = errors.getFieldError("password"); assertNotNull(error); - assertThat(messageSource.getMessage(error, Locale.ENGLISH), is("Size of Password is must be between 8 and 128")); + assertThat(messageSource.getMessage(error, Locale.ENGLISH), is("Size of Password must be between 8 and 128")); assertTrue(error.contains(ConstraintViolation.class)); assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString(), is("password")); } diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java index 725f4a96d9..482eba19a8 100644 --- a/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java +++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java @@ -72,7 +72,7 @@ public class SpringValidatorAdapterTests { @Before public void setupSpringValidatorAdapter() { - messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} is must be between {2} and {1}"); + messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} must be between {2} and {1}"); messageSource.addMessage("Same", Locale.ENGLISH, "{2} must be same value as {1}"); messageSource.addMessage("password", Locale.ENGLISH, "Password"); messageSource.addMessage("confirmPassword", Locale.ENGLISH, "Password(Confirm)"); @@ -98,7 +98,7 @@ public class SpringValidatorAdapterTests { assertThat(errors.getFieldValue("password"), is("pass")); FieldError error = errors.getFieldError("password"); assertNotNull(error); - assertThat(messageSource.getMessage(error, Locale.ENGLISH), is("Size of Password is must be between 8 and 128")); + assertThat(messageSource.getMessage(error, Locale.ENGLISH), is("Size of Password must be between 8 and 128")); assertTrue(error.contains(ConstraintViolation.class)); assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString(), is("password")); }