diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java index 083bb40c844..a03c6216316 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -29,8 +29,10 @@ import javax.validation.metadata.ConstraintDescriptor; import org.springframework.beans.NotReadablePropertyException; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.util.Assert; +import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; import org.springframework.validation.Validator; /** @@ -89,10 +91,31 @@ public class SpringValidatorAdapter implements Validator, javax.validation.Valid FieldError fieldError = errors.getFieldError(field); if (fieldError == null || !fieldError.isBindingFailure()) { try { - errors.rejectValue(field, - violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(), - getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor()), - violation.getMessage()); + String errorCode = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(); + Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor()); + if (errors instanceof BindingResult) { + // can do custom FieldError registration with invalid value from ConstraintViolation, + // as necessary for Hibernate Validator compatibility (non-indexed set path in field) + BindingResult bindingResult = (BindingResult) errors; + String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field); + String nestedField = bindingResult.getNestedPath() + field; + ObjectError error; + if ("".equals(nestedField)) { + error = new ObjectError( + errors.getObjectName(), errorCodes, errorArgs, violation.getMessage()); + } + else { + error = new FieldError( + errors.getObjectName(), nestedField, violation.getInvalidValue(), false, + errorCodes, errorArgs, violation.getMessage()); + } + bindingResult.addError(error); + } + else { + // got no BindingResult - can only do standard rejectValue call + // with automatic extraction of the current field value + errors.rejectValue(field, errorCode, errorArgs, violation.getMessage()); + } } catch (NotReadablePropertyException ex) { throw new IllegalStateException("JSR-303 validated property '" + field + diff --git a/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java b/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java index 7cdf0704a17..c6fc15faf75 100644 --- a/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java +++ b/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java @@ -22,6 +22,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays; import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; import javax.validation.Constraint; import javax.validation.ConstraintValidator; @@ -31,13 +34,14 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; import org.hibernate.validator.HibernateValidator; -import static org.junit.Assert.*; import org.junit.Test; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; +import static org.junit.Assert.*; + /** * @author Juergen Hoeller * @since 3.0 @@ -124,7 +128,53 @@ public class ValidatorFactoryTests { BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); validator.validate(person, result); assertEquals(1, result.getErrorCount()); - ObjectError fieldError = result.getGlobalError(); + ObjectError globalError = result.getGlobalError(); + System.out.println(Arrays.asList(globalError.getCodes())); + System.out.println(globalError.getDefaultMessage()); + } + + @Test + public void testSpringValidationWithErrorInListElement() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.getAddressList().add(new ValidAddress()); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(3, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("addressList[0].street"); + assertEquals("addressList[0].street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + } + + @Test + public void testSpringValidationWithErrorInSetElement() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.getAddressSet().add(new ValidAddress()); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(3, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("addressSet[].street"); + assertEquals("addressSet[].street", fieldError.getField()); System.out.println(Arrays.asList(fieldError.getCodes())); System.out.println(fieldError.getDefaultMessage()); } @@ -139,6 +189,12 @@ public class ValidatorFactoryTests { @Valid private ValidAddress address = new ValidAddress(); + @Valid + private List addressList = new LinkedList(); + + @Valid + private Set addressSet = new LinkedHashSet(); + public String getName() { return name; } @@ -154,6 +210,22 @@ public class ValidatorFactoryTests { public void setAddress(ValidAddress address) { this.address = address; } + + public List getAddressList() { + return addressList; + } + + public void setAddressList(List addressList) { + this.addressList = addressList; + } + + public Set getAddressSet() { + return addressSet; + } + + public void setAddressSet(Set addressSet) { + this.addressSet = addressSet; + } }