Hibernate JSR303验证和错误地生成的propertyPath [英] Hibernate JSR303 validation and incorrectly generated propertyPath

查看:128
本文介绍了Hibernate JSR303验证和错误地生成的propertyPath的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Spring MVC设置表单的JSR-303验证。我已经正确配置了所有的东西(或者至少我认为我是这样做的),并且验证工作大部分是正确的。但是,如果我有一个包含要验证的对象集合的命令对象,并且我使用@Valid对该集合进行了注释,则Hibernate JSR-303提供程序不会提供正确的propertyPath。 ContraintViolation对象中的propertyPath应该像 list [0] .bar list [1] .bar 一样填充,但Hibernate验证器仅提供 list [] .bar list [] .bar 。如果Spring的SpringValidatorAdaptor.validate()方法试图添加字段级错误(因为它内部需要在括号内存在一个数字),这会导致NumberFormatException。



使用spring- context-3.0.5和hibernate-validator-4.1.0.Final(我也试过4.0.2.GA和4.2.0.Beta2并得到了相同的结果),我写了一个小单元测试来说明这个问题: p>

  package com.foo; 

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validation;
import javax.validation.Validator;

import org.hibernate.validator.constraints.NotEmpty;
import org.junit.Test;
import org.springframework.util.AutoPopulatingList;

public class ValidatorTest {

class Person {
@NotEmpty
private String name;

@NotEmpty
@Valid
私人收藏< Foo> list = new AutoPopulatingList< Foo>(Foo.class);

public void setName(String name){
this.name = name;
}

public String getName(){
return name;
}

public Collection< Foo> getList(){
return list;
}

public void setList(Collection< Foo> foos){
this.list = foos;
}
}

class Foo {
@NotEmpty
private String bar;

public void setBar(String bar){
this.bar = bar;
}

public String getBar(){
return bar;


$ b $ @Test
public void testValidator()抛出异常{
Foo foo0 = new Foo();
foo0.setBar();

Foo foo1 = new Foo();
foo1.setBar();

收藏品< Foo> list = new ArrayList< ValidatorTest.Foo>();
list.add(foo0);
list.add(foo1);

Person person = new Person();
person.setName(Test Person);
person.setList(list);

Validator validator = Validation.buildDefaultValidatorFactory()。getValidator();
Set< ConstraintViolation< Person>> violation = validator.validate(person); (ConstraintViolation< Person> constraintViolation:violations){
System.out.println(constraintViolation);





$ / code $ / pre
$ b $ p上面的测试产生以下输出:

  ConstraintViolationImpl {interpolatedMessage ='可能不为空',propertyPath = list []。bar,rootBeanClass = class com。 foo.ValidatorTest $ Person,messageTemplate ='{org.hibernate.validator.constraints.NotEmpty.message}'} 
ConstraintViolationImpl {interpolatedMessage ='不得为空',propertyPath = list []。bar,rootBeanClass = class com.foo.ValidatorTest $ Person,messageTemplate ='{org.hibernate.validator.constraints.NotEmpty.message}'}

它产生的错误是正确的;然而,propertyPath不是(至少从我所理解的)。现在,如果我用Hibernate的JSR-303实现替换Apache的(org.apache.bval。 bundle-0.2-incubating - 使用此处指定的依赖关系),我得到输出我期望的。这是完全相同的测试,但使用Apache的JSR-303注释而不是Hibernate's。请注意现在存在于propertyPath字段中的索引:

  ConstraintViolationImpl {rootBean=com.foo.ValidatorTest$Person@5f989f84,propertyPath ='list [0] .bar',message ='不能为空',leafBean=com.foo.ValidatorTest$Foo@4393722c,value =} 
ConstraintViolationImpl {rootBean = com.foo.ValidatorTest $ Person @ 5f989f84,propertyPath ='list [1] .bar',message ='不得为空',leafBean=com.foo.ValidatorTest$Foo@528acf6e,value =}

由于各种原因,我可能会坚持使用Hibernate的JSR-303实现。有没有我正在做的事情导致Hibernate验证器不填充这些索引?我尽量避免在我的Spring控制器中手动执行错误处理。



感谢您提供的任何帮助!

解决方案

我在 Hibernate论坛,并且在那里得到了答案。我想在这里分享答案,以防其他人遇到此问题。



只需将Collection更改为List即可解决问题。以下是更新后的单元测试:

  package com.foo; 

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validation;
import javax.validation.Validator;

import org.hibernate.validator.constraints.NotEmpty;
import org.junit.Test;
import org.springframework.util.AutoPopulatingList;

public class ValidatorTest {

class Person {
@NotEmpty
private String name;

@NotEmpty
@Valid
私人列表< Foo> list = new AutoPopulatingList< Foo>(Foo.class);

public void setName(String name){
this.name = name;
}

public String getName(){
return name;
}

public List< Foo> getList(){
return list;


public void setList(List< Foo> foos){
this.list = foos;
}
}

class Foo {
@NotEmpty
private String bar;

public void setBar(String bar){
this.bar = bar;
}

public String getBar(){
return bar;


$ b $ @Test
public void testValidator()抛出异常{
Foo foo0 = new Foo();
foo0.setBar();

Foo foo1 = new Foo();
foo1.setBar();

列表< Foo> list = new ArrayList< ValidatorTest.Foo>();
list.add(foo0);
list.add(foo1);

Person person = new Person();
person.setName(Test Person);
person.setList(list);

Validator validator = Validation.buildDefaultValidatorFactory()。getValidator();
Set< ConstraintViolation< Person>> violation = validator.validate(person); (ConstraintViolation< Person> constraintViolation:violations){
System.out.println(constraintViolation);


}
}
}

测试(它现在包括索引):

$ pre codeonstraintViolationImpl {interpolatedMessage ='可能不是空的',propertyPath = list [1]。 bar,rootBeanClass = class com.foo.ValidatorTest $ Person,messageTemplate ='{org.hibernate.validator.constraints.NotEmpty.message}'}
ConstraintViolationImpl {interpolatedMessage ='不得为空',propertyPath = list [ 0] .bar,rootBeanClass = class com.foo.ValidatorTest $ Person,messageTemplate ='{org.hibernate.validator.constraints.NotEmpty.message}'}


I'm trying to set up JSR-303 validation of forms using Spring MVC. I had everything configured correctly (or at least I think I do), and validations are working mostly correctly. However, if I have a command object that contains a Collection of objects that I want validated, and I annotate that Collection with @Valid, the Hibernate JSR-303 provider is not providing the correct propertyPath. The propertyPath inside the ContraintViolation object should be populated like list[0].bar and list[1].bar, but the Hibernate validator is simply providing list[].bar and list[].bar. This causes a NumberFormatException when Spring's SpringValidatorAdaptor.validate() method tries to add field level errors (since it internally expects a number to exist within those brackets).

Using spring-context-3.0.5 and hibernate-validator-4.1.0.Final (I also tried 4.0.2.GA and 4.2.0.Beta2 and got the same results), I wrote a small unit test to illustrate the issue:

package com.foo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validation;
import javax.validation.Validator;

import org.hibernate.validator.constraints.NotEmpty;
import org.junit.Test;
import org.springframework.util.AutoPopulatingList;

public class ValidatorTest {

    class Person {
        @NotEmpty
        private String name;

        @NotEmpty
        @Valid
        private Collection<Foo> list = new AutoPopulatingList<Foo>(Foo.class);

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public Collection<Foo> getList() {
            return list;
        }

        public void setList(Collection<Foo> foos) {
            this.list = foos;
        }
    }

    class Foo {
        @NotEmpty
        private String bar;

        public void setBar(String bar) {
            this.bar = bar;
        }

        public String getBar() {
            return bar;
        }
    }

    @Test
    public void testValidator() throws Exception {
        Foo foo0 = new Foo();
        foo0.setBar("");

        Foo foo1 = new Foo();
        foo1.setBar("");

        Collection<Foo> list = new ArrayList<ValidatorTest.Foo>();
        list.add(foo0);
        list.add(foo1);

        Person person = new Person();
        person.setName("Test Person");
        person.setList(list);

        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Person>> violations = validator.validate(person);

        for (ConstraintViolation<Person> constraintViolation : violations) {
            System.out.println(constraintViolation);
        }
    }
}

The above test produces the following output:

ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=list[].bar, rootBeanClass=class com.foo.ValidatorTest$Person, messageTemplate='{org.hibernate.validator.constraints.NotEmpty.message}'}
ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=list[].bar, rootBeanClass=class com.foo.ValidatorTest$Person, messageTemplate='{org.hibernate.validator.constraints.NotEmpty.message}'}

The errors that it produces are correct; however, the propertyPath isn't (at least from what I understand).

Now, if I replace Hibernate's JSR-303 implementation with Apache's (org.apache.bval.bundle-0.2-incubating--using the dependencies noted here), I get output that I expect. This is the exact same test, but using Apache's JSR-303 annotations instead of Hibernate's. Note the indexes that now exist in the propertyPath field:

ConstraintViolationImpl{rootBean=com.foo.ValidatorTest$Person@5f989f84, propertyPath='list[0].bar', message='may not be empty', leafBean=com.foo.ValidatorTest$Foo@4393722c, value=}
ConstraintViolationImpl{rootBean=com.foo.ValidatorTest$Person@5f989f84, propertyPath='list[1].bar', message='may not be empty', leafBean=com.foo.ValidatorTest$Foo@528acf6e, value=}

For various reasons, I'm probably stuck with using Hibernate's JSR-303 implementation. Is there something that I'm doing that is causing the Hibernate validator not to populate those indexes? I'm trying to keep from doing manual error handling in my Spring controllers as much as possible.

Thanks for any help that you're able to provide!

解决方案

I asked this question on the Hibernate forums as well, and it got answered there. I wanted to share the answer here in case anyone else encounters this issue.

Simply changing the Collection to a List solves the problem. Here's the updated unit test:

package com.foo;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validation;
import javax.validation.Validator;

import org.hibernate.validator.constraints.NotEmpty;
import org.junit.Test;
import org.springframework.util.AutoPopulatingList;

public class ValidatorTest {

    class Person {
        @NotEmpty
        private String name;

        @NotEmpty
        @Valid
        private List<Foo> list = new AutoPopulatingList<Foo>(Foo.class);

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public List<Foo> getList() {
            return list;
        }

        public void setList(List<Foo> foos) {
            this.list = foos;
        }
    }

    class Foo {
        @NotEmpty
        private String bar;

        public void setBar(String bar) {
            this.bar = bar;
        }

        public String getBar() {
            return bar;
        }
    }

    @Test
    public void testValidator() throws Exception {
        Foo foo0 = new Foo();
        foo0.setBar("");

        Foo foo1 = new Foo();
        foo1.setBar("");

        List<Foo> list = new ArrayList<ValidatorTest.Foo>();
        list.add(foo0);
        list.add(foo1);

        Person person = new Person();
        person.setName("Test Person");
        person.setList(list);

        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Person>> violations = validator.validate(person);

        for (ConstraintViolation<Person> constraintViolation : violations) {
            System.out.println(constraintViolation);
        }
    }
}

And the output from the above test (which now includes indexes):

ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=list[1].bar, rootBeanClass=class com.foo.ValidatorTest$Person, messageTemplate='{org.hibernate.validator.constraints.NotEmpty.message}'}
ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=list[0].bar, rootBeanClass=class com.foo.ValidatorTest$Person, messageTemplate='{org.hibernate.validator.constraints.NotEmpty.message}'}

这篇关于Hibernate JSR303验证和错误地生成的propertyPath的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆