Skip to content

Commit d0e9328

Browse files
committed
SpringValidatorAdapter properly handles HV-5-style list constraint violations
Issue: SPR-15082
1 parent b06423a commit d0e9328

File tree

2 files changed

+70
-3
lines changed

2 files changed

+70
-3
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -255,7 +255,7 @@ protected MessageSourceResolvable getResolvableField(String objectName, String f
255255
protected Object getRejectedValue(String field, ConstraintViolation<Object> violation, BindingResult bindingResult) {
256256
Object invalidValue = violation.getInvalidValue();
257257
if (!"".equals(field) && (invalidValue == violation.getLeafBean() ||
258-
(field.contains(".") && !field.contains("[]")))) {
258+
(!field.contains("[]") && (field.contains("[") || field.contains("."))))) {
259259
// Possibly a bean constraint with property path: retrieve the actual property value.
260260
// However, explicitly avoid this for "address[]" style paths that we can't handle.
261261
invalidValue = bindingResult.getRawFieldValue(field);

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

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -41,6 +41,7 @@
4141
import org.springframework.beans.factory.annotation.Autowired;
4242
import org.springframework.context.ConfigurableApplicationContext;
4343
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
44+
import org.springframework.core.convert.support.DefaultConversionService;
4445
import org.springframework.core.env.Environment;
4546
import org.springframework.validation.BeanPropertyBindingResult;
4647
import org.springframework.validation.Errors;
@@ -255,6 +256,23 @@ public void testValidationWithOptionalField() throws Exception {
255256
assertNull(rejected);
256257
}
257258

259+
@Test
260+
public void testListValidation() throws Exception {
261+
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
262+
validator.afterPropertiesSet();
263+
264+
ListContainer listContainer = new ListContainer();
265+
listContainer.addString("A");
266+
listContainer.addString("X");
267+
268+
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(listContainer, "listContainer");
269+
errors.initConversion(new DefaultConversionService());
270+
validator.validate(listContainer, errors);
271+
272+
FieldError fieldError = errors.getFieldError("list[1]");
273+
assertEquals("X", errors.getFieldValue("list[1]"));
274+
}
275+
258276

259277
@NameAddressValid
260278
public static class ValidPerson {
@@ -424,4 +442,53 @@ public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
424442
}
425443
}
426444

445+
446+
public static class ListContainer {
447+
448+
@NotXList
449+
private List<String> list = new LinkedList<>();
450+
451+
public void addString(String value) {
452+
list.add(value);
453+
}
454+
455+
public List<String> getList() {
456+
return list;
457+
}
458+
}
459+
460+
461+
@Retention(RetentionPolicy.RUNTIME)
462+
@Target(ElementType.FIELD)
463+
@Constraint(validatedBy = NotXListValidator.class)
464+
public @interface NotXList {
465+
466+
String message() default "Should not be X";
467+
468+
Class<?>[] groups() default { };
469+
470+
Class<? extends Payload>[] payload() default {};
471+
}
472+
473+
474+
public static class NotXListValidator implements ConstraintValidator<NotXList, List<String>> {
475+
476+
@Override
477+
public void initialize(NotXList constraintAnnotation) {
478+
}
479+
480+
@Override
481+
public boolean isValid(List<String> list, ConstraintValidatorContext context) {
482+
context.disableDefaultConstraintViolation();
483+
boolean valid = true;
484+
for (int i = 0; i < list.size(); i++) {
485+
if ("X".equals(list.get(i))) {
486+
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addBeanNode().inIterable().atIndex(i).addConstraintViolation();
487+
valid = false;
488+
}
489+
}
490+
return valid;
491+
}
492+
}
493+
427494
}

0 commit comments

Comments
 (0)