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 6e019b38dd..aa88b18c57 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,12 +117,12 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. */ protected void processConstraintViolations(Set> violations, Errors errors) { for (ConstraintViolation violation : violations) { - String field = violation.getPropertyPath().toString(); + String field = determineField(violation); FieldError fieldError = errors.getFieldError(field); if (fieldError == null || !fieldError.isBindingFailure()) { try { ConstraintDescriptor cd = violation.getConstraintDescriptor(); - String errorCode = cd.getAnnotation().annotationType().getSimpleName(); + String errorCode = determineErrorCode(cd); Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, cd); if (errors instanceof BindingResult) { // Can do custom FieldError registration with invalid value from ConstraintViolation, @@ -135,16 +135,10 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. errors.getObjectName(), errorCodes, errorArgs, violation.getMessage())); } else { - Object invalidValue = violation.getInvalidValue(); - if (!"".equals(field) && (invalidValue == violation.getLeafBean() || - (field.contains(".") && !field.contains("[]")))) { - // Possibly a bean constraint with property path: retrieve the actual property value. - // However, explicitly avoid this for "address[]" style paths that we can't handle. - invalidValue = bindingResult.getRawFieldValue(field); - } + Object rejectedValue = getRejectedValue(field, violation, bindingResult); String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field); bindingResult.addError(new FieldError( - errors.getObjectName(), nestedField, invalidValue, false, + errors.getObjectName(), nestedField, rejectedValue, false, errorCodes, errorArgs, violation.getMessage())); } } @@ -163,6 +157,35 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. } } + /** + * Determine a field for the given constraint violation. + *

The default implementation returns the stringified property path. + * @param violation the current JSR-303 ConstraintViolation + * @return the Spring-reported field (for use with {@link Errors}) + * @since 4.2 + * @see javax.validation.ConstraintViolation#getPropertyPath() + * @see org.springframework.validation.FieldError#getField() + */ + protected String determineField(ConstraintViolation violation) { + return violation.getPropertyPath().toString(); + } + + /** + * Determine a Spring-reported error code for the given constraint descriptor. + *

The default implementation returns the simple class name of the descriptor's + * annotation type. Note that the configured + * {@link org.springframework.validation.MessageCodesResolver} will automatically + * generate error code variations which include the object name and the field name. + * @param descriptor the JSR-303 ConstraintDescriptor for the current violation + * @return a corresponding error code (for use with {@link Errors}) + * @since 4.2 + * @see javax.validation.metadata.ConstraintDescriptor#getAnnotation() + * @see org.springframework.validation.MessageCodesResolver + */ + protected String determineErrorCode(ConstraintDescriptor descriptor) { + return descriptor.getAnnotation().annotationType().getSimpleName(); + } + /** * Return FieldError arguments for a validation error on the given field. * Invoked for each violated constraint. @@ -196,6 +219,29 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. return arguments.toArray(new Object[arguments.size()]); } + /** + * Extract the rejected value behind the given constraint violation, + * for exposure through the Spring errors representation. + * @param field the field that caused the binding error + * @param violation the corresponding JSR-303 ConstraintViolation + * @param bindingResult a Spring BindingResult for the backing object + * which contains the current field's value + * @return the invalid value to expose as part of the field error + * @since 4.2 + * @see javax.validation.ConstraintViolation#getInvalidValue() + * @see org.springframework.validation.FieldError#getRejectedValue() + */ + protected Object getRejectedValue(String field, ConstraintViolation violation, BindingResult bindingResult) { + Object invalidValue = violation.getInvalidValue(); + if (!"".equals(field) && (invalidValue == violation.getLeafBean() || + (field.contains(".") && !field.contains("[]")))) { + // Possibly a bean constraint with property path: retrieve the actual property value. + // However, explicitly avoid this for "address[]" style paths that we can't handle. + invalidValue = bindingResult.getRawFieldValue(field); + } + return invalidValue; + } + //--------------------------------------------------------------------- // Implementation of JSR-303 Validator interface