@@ -165,27 +165,15 @@ protected void processConstraintViolations(Set<ConstraintViolation<Object>> viol
165165 String nestedField = bindingResult .getNestedPath () + field ;
166166 if (nestedField .isEmpty ()) {
167167 String [] errorCodes = bindingResult .resolveMessageCodes (errorCode );
168- ObjectError error = new ObjectError (
169- errors .getObjectName (), errorCodes , errorArgs , violation .getMessage ()) {
170- @ Override
171- public boolean shouldRenderDefaultMessage () {
172- return requiresMessageFormat (violation );
173- }
174- };
175- error .wrap (violation );
168+ ObjectError error = new ViolationObjectError (
169+ errors .getObjectName (), errorCodes , errorArgs , violation , this );
176170 bindingResult .addError (error );
177171 }
178172 else {
179173 Object rejectedValue = getRejectedValue (field , violation , bindingResult );
180174 String [] errorCodes = bindingResult .resolveMessageCodes (errorCode , field );
181- FieldError error = new FieldError (errors .getObjectName (), nestedField ,
182- rejectedValue , false , errorCodes , errorArgs , violation .getMessage ()) {
183- @ Override
184- public boolean shouldRenderDefaultMessage () {
185- return requiresMessageFormat (violation );
186- }
187- };
188- error .wrap (violation );
175+ FieldError error = new ViolationFieldError (errors .getObjectName (), nestedField ,
176+ rejectedValue , errorCodes , errorArgs , violation , this );
189177 bindingResult .addError (error );
190178 }
191179 }
@@ -307,29 +295,6 @@ protected MessageSourceResolvable getResolvableField(String objectName, String f
307295 return new DefaultMessageSourceResolvable (codes , field );
308296 }
309297
310- /**
311- * Indicate whether this violation's interpolated message has remaining
312- * placeholders and therefore requires {@link java.text.MessageFormat}
313- * to be applied to it. Called for a Bean Validation defined message
314- * (coming out {@code ValidationMessages.properties}) when rendered
315- * as the default message in Spring's MessageSource.
316- * <p>The default implementation considers a Spring-style "{0}" placeholder
317- * for the field name as an indication for {@link java.text.MessageFormat}.
318- * Any other placeholder or escape syntax occurrences are typically a
319- * mismatch, coming out of regex pattern values or the like. Note that
320- * standard Bean Validation does not support "{0}" style placeholders at all;
321- * this is a feature typically used in Spring MessageSource resource bundles.
322- * @param violation the Bean Validation constraint violation, including
323- * BV-defined interpolation of named attribute references in its message
324- * @return {@code true} if {@code java.text.MessageFormat} is to be applied,
325- * or {@code false} if the violation's message should be used as-is
326- * @since 5.1.8
327- * @see #getArgumentsForConstraint
328- */
329- protected boolean requiresMessageFormat (ConstraintViolation <?> violation ) {
330- return violation .getMessage ().contains ("{0}" );
331- }
332-
333298 /**
334299 * Extract the rejected value behind the given constraint violation,
335300 * for exposure through the Spring errors representation.
@@ -354,6 +319,33 @@ protected Object getRejectedValue(String field, ConstraintViolation<Object> viol
354319 return invalidValue ;
355320 }
356321
322+ /**
323+ * Indicate whether this violation's interpolated message has remaining
324+ * placeholders and therefore requires {@link java.text.MessageFormat}
325+ * to be applied to it. Called for a Bean Validation defined message
326+ * (coming out {@code ValidationMessages.properties}) when rendered
327+ * as the default message in Spring's MessageSource.
328+ * <p>The default implementation considers a Spring-style "{0}" placeholder
329+ * for the field name as an indication for {@link java.text.MessageFormat}.
330+ * Any other placeholder or escape syntax occurrences are typically a
331+ * mismatch, coming out of regex pattern values or the like. Note that
332+ * standard Bean Validation does not support "{0}" style placeholders at all;
333+ * this is a feature typically used in Spring MessageSource resource bundles.
334+ * @param violation the Bean Validation constraint violation, including
335+ * BV-defined interpolation of named attribute references in its message
336+ * @return {@code true} if {@code java.text.MessageFormat} is to be applied,
337+ * or {@code false} if the violation's message should be used as-is
338+ * @since 5.1.8
339+ * @see #getArgumentsForConstraint
340+ */
341+ protected boolean requiresMessageFormat (ConstraintViolation <?> violation ) {
342+ return containsSpringStylePlaceholder (violation .getMessage ());
343+ }
344+
345+ private static boolean containsSpringStylePlaceholder (@ Nullable String message ) {
346+ return (message != null && message .contains ("{0}" ));
347+ }
348+
357349
358350 //---------------------------------------------------------------------
359351 // Implementation of JSR-303 Validator interface
@@ -436,6 +428,71 @@ public Object[] getArguments() {
436428 public String getDefaultMessage () {
437429 return this .resolvableString ;
438430 }
431+
432+ @ Override
433+ public String toString () {
434+ return this .resolvableString ;
435+ }
436+ }
437+
438+
439+ /**
440+ * Subclass of {@code ObjectError} with Spring-style default message rendering.
441+ */
442+ @ SuppressWarnings ("serial" )
443+ private static class ViolationObjectError extends ObjectError implements Serializable {
444+
445+ @ Nullable
446+ private transient SpringValidatorAdapter adapter ;
447+
448+ @ Nullable
449+ private transient ConstraintViolation <?> violation ;
450+
451+ public ViolationObjectError (String objectName , String [] codes , Object [] arguments ,
452+ ConstraintViolation <?> violation , SpringValidatorAdapter adapter ) {
453+
454+ super (objectName , codes , arguments , violation .getMessage ());
455+ this .adapter = adapter ;
456+ this .violation = violation ;
457+ wrap (violation );
458+ }
459+
460+ @ Override
461+ public boolean shouldRenderDefaultMessage () {
462+ return (this .adapter != null && this .violation != null ?
463+ this .adapter .requiresMessageFormat (this .violation ) :
464+ containsSpringStylePlaceholder (getDefaultMessage ()));
465+ }
466+ }
467+
468+
469+ /**
470+ * Subclass of {@code FieldError} with Spring-style default message rendering.
471+ */
472+ @ SuppressWarnings ("serial" )
473+ private static class ViolationFieldError extends FieldError implements Serializable {
474+
475+ @ Nullable
476+ private transient SpringValidatorAdapter adapter ;
477+
478+ @ Nullable
479+ private transient ConstraintViolation <?> violation ;
480+
481+ public ViolationFieldError (String objectName , String field , @ Nullable Object rejectedValue , String [] codes ,
482+ Object [] arguments , ConstraintViolation <?> violation , SpringValidatorAdapter adapter ) {
483+
484+ super (objectName , field , rejectedValue , false , codes , arguments , violation .getMessage ());
485+ this .adapter = adapter ;
486+ this .violation = violation ;
487+ wrap (violation );
488+ }
489+
490+ @ Override
491+ public boolean shouldRenderDefaultMessage () {
492+ return (this .adapter != null && this .violation != null ?
493+ this .adapter .requiresMessageFormat (this .violation ) :
494+ containsSpringStylePlaceholder (getDefaultMessage ()));
495+ }
439496 }
440497
441498}
0 commit comments