validator mvc example custom bindingresult bean java spring rest spring-mvc bean-validation

java - example - spring mvc validation bindingresult



Spring MVC-@Valid en la lista de beans en el servicio REST (7)

Creo que su mejor opción es envolver la lista: ¿Cómo validar el parámetro de solicitud si no es un bean en Spring MVC?

No hay manera de decir que el @Valid se aplica a los elementos de la colección.

En un servicio Spring MVC REST (json), tengo un método de controlador como este:

@RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public List<...> myMethod(@Valid @RequestBody List<MyBean> request, BindingResult bindingResult) {

Donde la clase MyBean tiene anotaciones de validación de bean.

Las validaciones no parecen tener lugar en este caso, aunque funciona bien para otros controladores.

No quiero encapsular la lista en un dto a esto que cambiaría la entrada json.

¿Por qué no hay validaciones para una lista de frijoles? ¿Cuáles son las alternativas?


Hay una forma elegante de envolver su solicitud en una java.util.List personalizada que actúa como List y JavaBean . mira aquí


Implemente su propio validador con org.springframework.validation.beanvalidation.LocalValidatorFactoryBean como miembro y llame a ese validador para cada elemento.

public class CheckOutValidator implements Validator { private Validator validator; @Override public void validate(Object target, Errors errors) { List request = (List) target; Iterator it = request.iterator() while(it.hasNext()) { MyBean b = it.next(); validator.validate(b, errors); } } //setters and getters }


Intente la validación directa. Algo como esto:

@Autowired Validator validator; @RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public Object myMethod(@RequestBody List<Object> request, BindingResult bindingResult) { for (int i = 0; i < request.size(); i++) { Object o = request.get(i); BeanPropertyBindingResult errors = new BeanPropertyBindingResult(o, String.format("o[%d]", i)); validator.validate(o, errors); if (errors.hasErrors()) bindingResult.addAllErrors(errors); } if (bindingResult.hasErrors()) ...


La única forma que podría encontrar para hacer esto es envolver la lista, esto también significa que la entrada JSON tendría que cambiar .

@RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public List<...> myMethod(@Valid @RequestBody List<MyBean> request, BindingResult bindingResult) {

se convierte en:

@RequestMapping(method = RequestMethod.POST, value = { "/doesntmatter" }) @ResponseBody public List<...> myMethod(@Valid @RequestBody MyBeanList request, BindingResult bindingResult) {

y también necesitamos:

import javax.validation.Valid; import java.util.List; public class MyBeanList { @Valid List<MyBean> list; //getters and setters.... }

Esto parece que también podría ser posible con un validatior personalizado para las listas, pero aún no he llegado tan lejos.

La anotación @Valid es parte de la API de Validación de Beans JSR-303 estándar, y no es una construcción específica de Spring. Spring MVC validará un objeto @Valid después de vincularlo durante tanto tiempo como se haya configurado un validador adecuado.

Referencia: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html


Si no desea escribir un contenedor para cada Lista que tiene, puede usar un contenedor genérico:

public class ListWrapper<E> { private List<E> list; public ListWrapper() { list = new ArrayList<>(); } public ListWrapper(List<E> list) { this.list = list; } @Valid public List<E> getList() { return list; } public void setList(List<E> list) { this.list = list; } public boolean add(E e) { return list.add(e); } public void clear() { list.clear(); } }


@Valid es una anotación JSR-303 y JSR-303 se aplica a la validación en JavaBeans. Una java.util.List no es un JavaBean (según la descripción oficial de un JavaBean), por lo que no puede validarse directamente utilizando un validador compatible con JSR-303. Esto es apoyado por dos observaciones.

La Sección 3.1.3 de la Especificación JSR-303 dice que:

Además de admitir la validación de instancias, también se admite la validación de gráficos de objetos. El resultado de una validación de gráfico se devuelve como un conjunto unificado de violaciones de restricciones. Considere la situación en la que el bean X contiene un campo de tipo Y. Al anotar el campo Y con la anotación @Valid , el Validador validará Y (y sus propiedades) cuando se valide X. El tipo exacto Z del valor contenido en el campo declarado de tipo Y (subclase, implementación) se determina en tiempo de ejecución. Se utilizan las definiciones de restricción de Z. Esto asegura un comportamiento polimórfico adecuado para las asociaciones marcadas con @Valid.

Los campos y propiedades con valores de colección, valores de matriz y generalmente iterables pueden decorarse con la anotación @Valid . Esto hace que los contenidos del iterador sean validados. Cualquier objeto que implemente java.lang.Iterable es compatible.

He marcado las piezas importantes de información en negrita. Esta sección implica que para que un tipo de colección sea validado, debe encapsularse dentro de un bean (implícito en Consider the situation where bean X contains a field of type Y ); y además, las colecciones no pueden ser validadas directamente (implícitas por los Collection-valued, array-valued and generally Iterable fields and properties may also be decorated , con énfasis en los campos y propiedades ).

Implementaciones reales JSR-303

Tengo una aplicación de ejemplo que prueba la validación de la colección con Hibernate Validator y Apache Beans Validator. Si ejecuta pruebas en esta muestra como mvn clean test -Phibernate (con Hibernate Validator) y mvn clean test -Papache (para Beans Validator), ambos se niegan a validar las colecciones directamente, lo que parece estar en línea con la especificación. Dado que Hibernate Validator es la implementación de referencia para JSR-303, esta muestra es una prueba más de que las colecciones deben encapsularse en un bean para validarse.

Con eso en claro, diría que también hay un problema de diseño al tratar de pasar una colección a un método de controlador directamente de la forma mostrada en la pregunta. Incluso si las validaciones funcionaran directamente en las colecciones, el método del controlador no podrá trabajar con representaciones de datos alternativas como XML personalizado, SOAP, ATOM, EDI, Google Protocol Buffers, etc. que no se asignan directamente a las colecciones. Para admitir esas representaciones, el controlador debe aceptar y devolver instancias de objetos. Eso requeriría encapsular la colección dentro de una instancia de objeto de cualquier manera. Por lo tanto, sería altamente recomendable envolver la List dentro de otro objeto como han sugerido otras respuestas.