我在JSR 303级别验证和spring时遇到错误,我想知道我是否以正确的方式进行设置。
我在spring(4.2.6.RELEASE)中使用hibernate-validator(5.2.4.Final)进行验证,在弹簧控制器内部进行典型设置,如:
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public SomeDto update(@PathVariable Integer id, @Valid @RequestBody SomeDto someDto) {
...
return someDto;
}
这适用于大多数设置,但是当验证目标包含一组使用类级别验证注释的对象时,SpringValidatorAdaptor在尝试查找原始值时失败
以下代码说明了问题:
要验证的目标类:
public class Base {
@Valid
Set<MyClass> myClassSet = new HashSet<>();
public Set<MyClass> getMyClassSet() {
return myClassSet;
}
具有类级别验证注释的类:
@CheckMyClass
public class MyClass {
String a;
String b;
public MyClass(final String a, final String b) {
this.a = a;
this.b = b;
}
}
约束:
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckMyClassValidator.class)
@Documented
public @interface CheckMyClass {
String message() default "Invalid class";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
验证
public class CheckMyClassValidator implements ConstraintValidator<CheckMyClass, MyClass> {
@Override
public void initialize(final CheckMyClass constraintAnnotation) {
}
@Override
public boolean isValid(final MyClass value, final ConstraintValidatorContext context) {
return false; // want it to fail for testing purposes
}
}
测试类:
@SpringBootApplication
public class SpringValidationTest {
@Bean
public org.springframework.validation.Validator validator() {
return new org.springframework.validation.beanvalidation.LocalValidatorFactoryBean();
}
private void doStandardValidation() {
Base base = createBase();
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Base>> violations = validator.validate(base);
for (ConstraintViolation<?> violation : violations) {
System.out.println(violation.getMessage());
}
}
private Base createBase() {
Base base = new Base();
base.getMyClassSet().add(new MyClass("a1", "b1"));
// base.getMyClassSet().add(new MyClass("a2", "b2"));
return base;
}
@PostConstruct
private void doSpringValidation() {
Base base = createBase();
org.springframework.validation.Validator validator = validator();
DataBinder binder = new DataBinder(base);
binder.setValidator(validator);
binder.validate();
BindingResult results = binder.getBindingResult();
for (ObjectError error : results.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
public static void main(String[] args) {
(new SpringValidationTest()).doStandardValidation();
System.out.println();
ApplicationContext applicationContext = SpringApplication.run(SpringValidationTest.class);
}
}
标准验证工作正常,但是当它被弹簧验证器包装时(如在典型的控制器设置中),它最终会出现异常(如下所示),试图查找属性的值:
Caused by: java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_45]
at java.lang.Integer.parseInt(Integer.java:592) ~[na:1.8.0_45]
at java.lang.Integer.parseInt(Integer.java:615) ~[na:1.8.0_45]
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:657) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
... 37 common frames omitted