2010-10-25 12 views
9

Tengo un formulario que quiero validar. Contiene 2 variables de dirección. dirección1 siempre tiene que ser validado, address2 tiene que ser validado basado en algunas condicionesSpring MVC y JSR-303 hibernate conditional validation

public class MyForm { 
    String name; 
    @Valid Address address1; 
    Address address2; 
} 

public class Address { 
    @NotEmpty 
    private String street; 
} 

mi controlador valida y se une de forma automática mi forma obj

@RequestMapping(...) 
public ModelAndView edit(
     @ModelAttribute("form") 
     @Valid 
     MyForm form, 
     BindingResult bindingResult, 
     ...) 

     if(someCondition) { 
      VALIDATE form.address2 USING JSR 303 

el problema es que si uso el validador LocalValidatorFactoryBean i no puede reutilizar el objeto BinidingResult provisto por Spring. El aprieto no va a funcionar como el objeto de destino del 'resultado' es 'MiFormulario' y no 'Dirección'

validate(form.getAddress2(), bindingResult) //won't work 

me pregunto ¿cuál es el/enfoque limpio estándar de hacer la validación condicional.

Estaba pensando en crear programáticamente un nuevo BindingResult en mi controlador.

final BindingResult bindingResultAddress2 = new BeanPropertyBindingResult(address2, "form"); 
validate(form.getAddress2(), bindingResultAddress2); 

pero luego la lista de errores que obtenemos de bindingResultAddress2 no se puede añadir a lo general 'bindingResult' como los nombres de campo no son correctas ('calle' en lugar de 'address2.street') y la unión no funcionará

Algún enfoque sucio sería extender BeanPropertyBindingResult para aceptar alguna cadena para agregar al nombre de los campos ... ¿tiene un mejor enfoque?

Respuesta

5

El enfoque estándar para la validación de las estructuras jerárquicas es utilizar pushNestedPath()/popNestedPath(), aunque no estoy seguro de cómo se juega con JSR-303:

bindingResult.pushNestedPath("address2"); 
validate(form.getAddress2(), bindingResult); 
bindingResult.popNestedPath(); 
+1

Gracias axtavt, funciona. Me pregunto si este es el mejor enfoque para hacerlo, por qué no hay ningún atributo de grupos en @Valid y si el concepto de grupos JSR-303 es la única forma de lograr la validación condicional – mickthompson

+3

Hay una solicitud de función para grupos en '@ Válido' : https://jira.springframework.org/browse/SPR-6373 – axtavt

+0

muy útil, gracias – mickthompson

1

nunca he probado a mí mismo, pero creo que la el enfoque correcto es usar validator groups.

+0

Desafortunadamente @Valid no tiene grupos – mickthompson

+0

Es desafortunado - vea mi comentario anterior.Creo que sería una gran adición a la especificación y que este nivel de practicidad debería ser favorecido por sobre el idealismo. –

+0

O para apaciguar a los idealistas, debemos dejar de llamar a esto un 'Marco de Validación de Bean' y comenzar a llamarlo 'Marco de Validación Java' y agregar soporte para argumentos de método y valores de retorno además de gráficos de objetos. –

0

En primer lugar, vamos a ver @javax.validation.Valid API

Marcos como una asociación en cascada. El objeto asociado será validado por cascada.

Cuando framework Spring utiliza @Valid como marcador para validar sus objetos de comando, se corrompe su propósito. Spring debería crear su propia anotación específica que especifique los grupos que deberían validarse.

Por desgracia, se debe utilizar la API de primavera Validador nativo si es necesario para validar algunos grupos

public void doSomething(Command command, Errors errors) { 
    new BeanValidationValidator(SomeUserCase.class, OtherUserCase.class) 
     .validate(command, errors); 

    if(errors.hasErrors()) { 

    } else { 

    } 
} 

BeanValidationValidator se puede implementar como

public class BeanValidationValidator implements Validator { 

    javax.validation.Validator validator = ValidatorUtil.getValidator(); 

    private Class [] groups; 

    public BeanValidationValidator(Class... groups) { 
     this.groups = groups; 
    } 

    public void validate(Object command, Errors errors) { 
     Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(command, groups); 

     for(ConstraintViolation<Object> constraintViolation: constraintViolationSet) { 
      errors.rejectValue(constraintViolation.getPropertyPath().toString(), null, constraintViolation.getMessage()); 
     } 
    } 

} 
+0

Disiento respetuosamente de que agregar grupos a la anotación @Valid sea una corrupción de su propósito. Lo veo como una mejora. @Valid dice "este objeto debe ser validado". Agregar grupos significaría efectivamente "este objeto debería validarse de esta manera". No hay ninguna razón por la que esa misma afirmación no pueda aplicarse a asociaciones en cascada para gráficos de objetos, así como a argumentos de métodos. Además, las especificaciones deben evolucionar con obvias adiciones valiosas; Agregar grupos a @Valid permitiría que muchos frameworks eliminen el código repetido. Las especificaciones deben favorecer el sentido práctico sobre el idealismo. –