Проверка Hibernate JSR303 и неправильно сгенерированный propertyPath - PullRequest
4 голосов
/ 20 апреля 2011

Я пытаюсь настроить проверку форм JSR-303 с помощью Spring MVC. У меня все настроено правильно (или, по крайней мере, я так думаю), и проверки работают в основном правильно. Однако, если у меня есть объект команды, который содержит коллекцию объектов, которые я хочу проверить, и я аннотирую эту коллекцию с помощью @Valid, поставщик Hibernate JSR-303 не предоставляет правильный propertyPath. Свойство propertyPath внутри объекта ContraintViolation должно быть заполнено как list[0].bar и list[1].bar, но валидатор Hibernate просто предоставляет list[].bar и list[].bar. Это вызывает NumberFormatException, когда метод SpringValidatorAdaptor.validate () Spring пытается добавить ошибки на уровне поля (поскольку внутри него ожидается, что число существует в этих скобках).

Используя 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 не является (по крайней мере из того, что я понимаю).

Теперь, если я заменим реализацию JSR-303 Hibernate на реализацию Apache (org.apache.bval.bundle-0.2 - используя зависимости, отмеченные здесь ), я получу ожидаемый вывод. Это точно такой же тест, но с использованием аннотаций Apache JSR-303 вместо Hibernate. Обратите внимание на индексы, которые теперь существуют в поле 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=}

По разным причинам я, вероятно, застрял с использованием реализации JSR-303 в Hibernate. Что-то, что я делаю, заставляет валидатор Hibernate не заполнять эти индексы? Я стараюсь максимально избегать ручной обработки ошибок в моих контроллерах Spring.

Спасибо за любую помощь, которую вы можете оказать!

1 Ответ

5 голосов
/ 21 апреля 2011

Я также задавал этот вопрос на форумах 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}'}
...