2011-04-20 4 views
4

Spring MVC를 사용하여 JSR-303의 폼 유효성 검사를 설정하려고합니다. 모든 것이 올바르게 구성되었거나 (적어도 필자는 그렇게 생각합니다) 유효성 검사가 대부분 올바르게 작동합니다. 그러나, 내가 유효성을 검사하고자하는 객체들의 콜렉션을 포함하고있는 커맨드 객체를 가지고 있고 그 콜렉션에 @Valid로 주석을 붙이면, Hibernate JSR-303 제공자는 올바른 propertyPath를 제공하지 않는다. ContraintViolation 객체 안의 propertyPath는 list[0].barlist[1].bar처럼 채워 져야한다. 그러나 Hibernate 검사기는 단지 list[].barlist[].bar을 제공하고있다. 이로 인해 Spring의 SpringValidatorAdaptor.validate() 메소드가 필드 레벨 오류를 추가하려고 시도 할 때 NumberFormatException이 발생합니다 (내부적으로 대괄호 내에 숫자가 존재할 것으로 예상하기 때문에).Hibernate JSR303 검증과 잘못 생성 된 propertyPath

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 - 종속성 인 here 사용)로 대체하면 예상 한 결과를 얻는다. 이것은 정확히 동일한 테스트이지만 Hibernate 대신 Apache의 JSR-303 주석을 사용합니다. 이제 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 validator가 그 인덱스를 채우지 못하게하는 것을 내가하고있는 어떤 것이 있는가? 가능한 한 내 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}'} 
여기서 업데이트의 테스트 유닛
관련 문제