2011-04-20 1 views
4

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

Использование 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}'} 

ошибки, которые она производит являются правильными; однако свойствоPath не является (по крайней мере, из того, что я понимаю).

Теперь, если я заменил реализацию JSR-303 Hibernate на Apache (org.apache.bval.bundle-0.2-incubating - используя отмеченные зависимости here), я получаю вывод, который я ожидаю. Это тот же самый тест, но с использованием аннотаций JSR-303 от Apache вместо Hibernate. Обратите внимание на индексы, которые сейчас существуют в области PropertyPath:

ConstraintViolationImpl{[email protected], propertyPath='list[0].bar', message='may not be empty', [email protected], value=} 
ConstraintViolationImpl{[email protected], propertyPath='list[1].bar', message='may not be empty', [email protected], value=} 

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

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

ответ

5

Я также задал этот вопрос на Hibernate forums, и там он получил ответ. Я хотел бы поделиться этим ответом здесь, если кто-то еще столкнется с этой проблемой.

Простое изменение коллекции в список решает проблему. Вот обновленный тестовый модуль:

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