Browse Source

SpringValidationAdapter properly detects invalid value for JSR-303 field-level bean constraints

Issue: SPR-9332
pull/218/head
Juergen Hoeller 12 years ago committed by unknown
parent
commit
8e75eee9b2
  1. 17
      spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
  2. 68
      spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@ -99,7 +99,8 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. @@ -99,7 +99,8 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
}
}
}
processConstraintViolations(this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors);
processConstraintViolations(
this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors);
}
/**
@ -114,10 +115,11 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. @@ -114,10 +115,11 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
FieldError fieldError = errors.getFieldError(field);
if (fieldError == null || !fieldError.isBindingFailure()) {
try {
String errorCode = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName();
Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor());
ConstraintDescriptor<?> cd = violation.getConstraintDescriptor();
String errorCode = cd.getAnnotation().annotationType().getSimpleName();
Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, cd);
if (errors instanceof BindingResult) {
// can do custom FieldError registration with invalid value from ConstraintViolation,
// 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 nestedField = bindingResult.getNestedPath() + field;
@ -128,8 +130,9 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. @@ -128,8 +130,9 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
}
else {
Object invalidValue = violation.getInvalidValue();
if (!"".equals(field) && invalidValue == violation.getLeafBean()) {
// bean constraint with property path: retrieve the actual property value
if (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);
}
String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field);

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@ -30,6 +30,7 @@ import javax.validation.Constraint; @@ -30,6 +30,7 @@ import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolation;
import javax.validation.Payload;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
@ -37,6 +38,7 @@ import org.hibernate.validator.HibernateValidator; @@ -37,6 +38,7 @@ import org.hibernate.validator.HibernateValidator;
import org.junit.Test;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
@ -193,6 +195,18 @@ public class ValidatorFactoryTests { @@ -193,6 +195,18 @@ public class ValidatorFactoryTests {
System.out.println(fieldError.getDefaultMessage());
}
@Test
public void testInnerBeanValidation() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
MainBean mainBean = new MainBean();
Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean");
validator.validate(mainBean, errors);
Object rejected = errors.getFieldValue("inner.value");
assertNull(rejected);
}
@NameAddressValid
public static class ValidPerson {
@ -242,7 +256,6 @@ public class ValidatorFactoryTests { @@ -242,7 +256,6 @@ public class ValidatorFactoryTests {
}
}
public static class ValidAddress {
@NotNull
@ -257,7 +270,6 @@ public class ValidatorFactoryTests { @@ -257,7 +270,6 @@ public class ValidatorFactoryTests {
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NameAddressValidator.class)
@ -270,7 +282,6 @@ public class ValidatorFactoryTests { @@ -270,7 +282,6 @@ public class ValidatorFactoryTests {
Class<?>[] payload() default {};
}
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> {
@Override
@ -283,4 +294,53 @@ public class ValidatorFactoryTests { @@ -283,4 +294,53 @@ public class ValidatorFactoryTests {
}
}
public static class MainBean {
@InnerValid
private InnerBean inner = new InnerBean();
public InnerBean getInner() {
return inner;
}
}
public static class InnerBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy=InnerValidator.class)
public static @interface InnerValid {
String message() default "NOT VALID";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default {};
}
public static class InnerValidator implements ConstraintValidator<InnerValid, InnerBean> {
@Override
public void initialize(InnerValid constraintAnnotation) {
}
@Override
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
if (bean.getValue() == null) {
context.buildConstraintViolationWithTemplate("NULL"). addNode("value").addConstraintViolation();
return false;
}
return true;
}
}
}

Loading…
Cancel
Save