Skip to content

Commit 1e2f491

Browse files
committed
SpringValidatorAdapter accepts non-indexed set paths (for Hibernate Validator compatibility; SPR-8634)
1 parent f91f778 commit 1e2f491

File tree

2 files changed

+102
-7
lines changed

2 files changed

+102
-7
lines changed

org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,8 +29,10 @@
2929
import org.springframework.beans.NotReadablePropertyException;
3030
import org.springframework.context.support.DefaultMessageSourceResolvable;
3131
import org.springframework.util.Assert;
32+
import org.springframework.validation.BindingResult;
3233
import org.springframework.validation.Errors;
3334
import org.springframework.validation.FieldError;
35+
import org.springframework.validation.ObjectError;
3436
import org.springframework.validation.Validator;
3537

3638
/**
@@ -89,10 +91,31 @@ public void validate(Object target, Errors errors) {
8991
FieldError fieldError = errors.getFieldError(field);
9092
if (fieldError == null || !fieldError.isBindingFailure()) {
9193
try {
92-
errors.rejectValue(field,
93-
violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(),
94-
getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor()),
95-
violation.getMessage());
94+
String errorCode = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName();
95+
Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor());
96+
if (errors instanceof BindingResult) {
97+
// can do custom FieldError registration with invalid value from ConstraintViolation,
98+
// as necessary for Hibernate Validator compatibility (non-indexed set path in field)
99+
BindingResult bindingResult = (BindingResult) errors;
100+
String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field);
101+
String nestedField = bindingResult.getNestedPath() + field;
102+
ObjectError error;
103+
if ("".equals(nestedField)) {
104+
error = new ObjectError(
105+
errors.getObjectName(), errorCodes, errorArgs, violation.getMessage());
106+
}
107+
else {
108+
error = new FieldError(
109+
errors.getObjectName(), nestedField, violation.getInvalidValue(), false,
110+
errorCodes, errorArgs, violation.getMessage());
111+
}
112+
bindingResult.addError(error);
113+
}
114+
else {
115+
// got no BindingResult - can only do standard rejectValue call
116+
// with automatic extraction of the current field value
117+
errors.rejectValue(field, errorCode, errorArgs, violation.getMessage());
118+
}
96119
}
97120
catch (NotReadablePropertyException ex) {
98121
throw new IllegalStateException("JSR-303 validated property '" + field +

org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
import java.lang.annotation.Target;
2323
import java.util.Arrays;
2424
import java.util.Iterator;
25+
import java.util.LinkedHashSet;
26+
import java.util.LinkedList;
27+
import java.util.List;
2528
import java.util.Set;
2629
import javax.validation.Constraint;
2730
import javax.validation.ConstraintValidator;
@@ -31,13 +34,14 @@
3134
import javax.validation.constraints.NotNull;
3235

3336
import org.hibernate.validator.HibernateValidator;
34-
import static org.junit.Assert.*;
3537
import org.junit.Test;
3638

3739
import org.springframework.validation.BeanPropertyBindingResult;
3840
import org.springframework.validation.FieldError;
3941
import org.springframework.validation.ObjectError;
4042

43+
import static org.junit.Assert.*;
44+
4145
/**
4246
* @author Juergen Hoeller
4347
* @since 3.0
@@ -124,7 +128,53 @@ public void testSpringValidationWithClassLevel() throws Exception {
124128
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
125129
validator.validate(person, result);
126130
assertEquals(1, result.getErrorCount());
127-
ObjectError fieldError = result.getGlobalError();
131+
ObjectError globalError = result.getGlobalError();
132+
System.out.println(Arrays.asList(globalError.getCodes()));
133+
System.out.println(globalError.getDefaultMessage());
134+
}
135+
136+
@Test
137+
public void testSpringValidationWithErrorInListElement() throws Exception {
138+
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
139+
validator.afterPropertiesSet();
140+
ValidPerson person = new ValidPerson();
141+
person.getAddressList().add(new ValidAddress());
142+
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
143+
validator.validate(person, result);
144+
assertEquals(3, result.getErrorCount());
145+
FieldError fieldError = result.getFieldError("name");
146+
assertEquals("name", fieldError.getField());
147+
System.out.println(Arrays.asList(fieldError.getCodes()));
148+
System.out.println(fieldError.getDefaultMessage());
149+
fieldError = result.getFieldError("address.street");
150+
assertEquals("address.street", fieldError.getField());
151+
System.out.println(Arrays.asList(fieldError.getCodes()));
152+
System.out.println(fieldError.getDefaultMessage());
153+
fieldError = result.getFieldError("addressList[0].street");
154+
assertEquals("addressList[0].street", fieldError.getField());
155+
System.out.println(Arrays.asList(fieldError.getCodes()));
156+
System.out.println(fieldError.getDefaultMessage());
157+
}
158+
159+
@Test
160+
public void testSpringValidationWithErrorInSetElement() throws Exception {
161+
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
162+
validator.afterPropertiesSet();
163+
ValidPerson person = new ValidPerson();
164+
person.getAddressSet().add(new ValidAddress());
165+
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
166+
validator.validate(person, result);
167+
assertEquals(3, result.getErrorCount());
168+
FieldError fieldError = result.getFieldError("name");
169+
assertEquals("name", fieldError.getField());
170+
System.out.println(Arrays.asList(fieldError.getCodes()));
171+
System.out.println(fieldError.getDefaultMessage());
172+
fieldError = result.getFieldError("address.street");
173+
assertEquals("address.street", fieldError.getField());
174+
System.out.println(Arrays.asList(fieldError.getCodes()));
175+
System.out.println(fieldError.getDefaultMessage());
176+
fieldError = result.getFieldError("addressSet[].street");
177+
assertEquals("addressSet[].street", fieldError.getField());
128178
System.out.println(Arrays.asList(fieldError.getCodes()));
129179
System.out.println(fieldError.getDefaultMessage());
130180
}
@@ -139,6 +189,12 @@ public static class ValidPerson {
139189
@Valid
140190
private ValidAddress address = new ValidAddress();
141191

192+
@Valid
193+
private List<ValidAddress> addressList = new LinkedList<ValidAddress>();
194+
195+
@Valid
196+
private Set<ValidAddress> addressSet = new LinkedHashSet<ValidAddress>();
197+
142198
public String getName() {
143199
return name;
144200
}
@@ -154,6 +210,22 @@ public ValidAddress getAddress() {
154210
public void setAddress(ValidAddress address) {
155211
this.address = address;
156212
}
213+
214+
public List<ValidAddress> getAddressList() {
215+
return addressList;
216+
}
217+
218+
public void setAddressList(List<ValidAddress> addressList) {
219+
this.addressList = addressList;
220+
}
221+
222+
public Set<ValidAddress> getAddressSet() {
223+
return addressSet;
224+
}
225+
226+
public void setAddressSet(Set<ValidAddress> addressSet) {
227+
this.addressSet = addressSet;
228+
}
157229
}
158230

159231

0 commit comments

Comments
 (0)