4

Spring MVC を使用してフォームの JSR-303 検証を設定しようとしています。すべてが正しく構成されており (または、少なくとも構成されていると思います)、検証はほとんど正しく機能しています。ただし、検証したいオブジェクトのコレクションを含むコマンド オブジェクトがあり、そのコレクションに @Valid の注釈を付けると、Hibernate JSR-303 プロバイダーは正しい propertyPath を提供しません。ContraintViolation オブジェクト内の propertyPath はlist[0].barandlist[1].barのように入力する必要がありますが、Hibernate バリデーターは単純に and を提供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 も試しましたが、同じ結果が得られました)、問題を説明する小さな単体テストを作成しました。 :

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);
        }
    }
}

上記のテストでは、次の出力が生成されます。

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}'}

生成されるエラーは正しいです。ただし、propertyPath はそうではありません (少なくとも私が理解していることから)。

ここで、Hibernate の JSR-303 実装を Apache の実装 (org.apache.bval.bundle-0.2-incubating -ここに記載されている依存関係を使用) に置き換えると、期待どおりの出力が得られます。これはまったく同じテストですが、Hibernate の代わりに Apache の JSR-303 アノテーションを使用しています。propertyPath フィールドに存在するインデックスに注意してください。

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=}

さまざまな理由から、私はおそらく Hibernate の JSR-303 実装の使用に固執しています。Hibernate バリデーターがこれらのインデックスにデータを入力しない原因となっていることはありますか? Spring コントローラーで手動エラー処理をできる限り行わないようにしています。

ご協力いただきありがとうございます。

4

2 に答える 2

5

Hibernate フォーラムでもこの質問をしたところ、そこで回答が得られました。他の誰かがこの問題に遭遇した場合に備えて、ここで回答を共有したいと思います。

コレクションをリストに変更するだけで問題が解決します。更新された単体テストは次のとおりです。

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);
        }
    }
}

そして、上記のテストからの出力 (現在はインデックスが含まれています):

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}'}
于 2011-04-20T22:27:43.377 に答える