Cuando construyo un servicio web RESTful usando Spring MVC, siento que he encontrado una situación difícil cuando intento combinar la deserialización de Jackson JSON y la validación de beans JSR-303.¿Cómo puedo admitir la validación JSR-303 y el mapeo Jackson JSON juntos de manera efectiva?
Una de las cosas buenas de la validación JSR-303 es que uno puede devolver todos los errores de validación asociados con un objeto de destino en lugar de simplemente fallar en la primera violación de restricción (aunque hay un modo de falla rápida si desea usarlo)
Imagine un escenario en el que tienen una carga útil JSON como:
{
"firstname": "Joe",
"surname": "Bloggs",
"age": 25
}
Y entonces usted tiene el objeto que desea mapear:
public class Person {
@NotNull
private String firstname;
@NotNull
private String surname;
@Min(value = 0)
private int age;
...
}
Mi problema con esta disposición es que si el cliente envía un String como el valor de "edad", todo el proceso de deserialización de Jackson fallará sin poder apuntar específicamente al motivo por el cual falló (es decir, nunca llegaremos a validar). Imagínese, entonces, esta carga útil:
{
"age": "invalid"
}
En este caso, lo que me gustaría volver sería una respuesta "errores", tales como:
{
"errors" : [
"error": {
"field": "firstname",
"message": "Must not be null",
},
"error": {
"field": "surname",
"message": "Must not be null",
},
"error": {
"field": "age",
"message": "Must be numeric value greater than or equal 0",
}
]
}
La forma más sencilla de solucionar este problema sería simplemente especifique el campo "edad" como tipo "Cadena" y luego convierta el valor al pasarlo a, por ejemplo, la capa de persistencia. Sin embargo, realmente no me gusta la idea de recurrir a objetos de transferencia de datos que usan cadenas de forma generalizada; parece incorrecto hacerlo en términos de preservar un diseño limpio.
Otra opción pensé sería la creación de una clase como:
public abstract class BindableValue<T> {
private String stringValue;
private T value;
public T getValue() {
if(value == null) {
value = fromString(stringValue);
}
return value;
}
protected abstract T fromString(String stringValue);
}
pude luego crear implementaciones como IntegerValue, longValue, DateTimeValue etc., por supuesto, también la escritura adaptadores de tipo personalizado para Jackson. Y entonces mi clase de persona puede ser:
public class Person {
@NotNull
private StringValue firstname;
@NotNull
private StringValue surname;
@Min(value = 0)
private IntegerValue age;
...
}
Esto es casi lo que quiera pero, por desgracia, los JSR-303 anotaciones tales como @NotNull y @Min no van a reconocer mis implementaciones BindableValue.
Entonces, ¿alguien puede explicar una forma en que podría resolver este problema de una manera más limpia?
hice prueba simple y si envía JSON desde el primer puesto de drewzilla sin un valor numérico que se obtiene: { "código": 400, "mensaje" : "No se puede procesar JSON" }. Entonces, dropwizard no resuelve este problema. – wjtk
Mi comentario fue en relación con la publicación en su forma original. DropWizard no cambia la semántica de Bean Validation, pero resuelve el problema de cómo uno permite su uso. Otros marcos como Spring pueden proporcionar esto también, en este punto. Pero tenga en cuenta el momento del comentario original. – StaxMan