在使用Spring MVC构建RESTful Web服务时,我觉得在尝试组合Jackson JSON反序列化和JSR-303 bean验证时遇到了棘手的情况.
关于JSR-303验证的一个好处是,可以返回与目标对象关联的所有验证错误,而不是仅在第一个约束违规时失败(尽管如果要使用它,则存在失败快速模式).
想象一下你有一个JSON有效载荷的场景,例如:
{ "firstname": "Joe", "surname": "Bloggs", "age": 25 }
然后你有想要映射到的对象:
public class Person { @NotNull private String firstname; @NotNull private String surname; @Min(value = 0) private int age; ... }
我对此设置的问题是,如果客户端发送一个字符串作为"年龄"的值,整个杰克逊反序列化过程将失败而不能专门针对它失败的原因(即我们永远不会得到验证) ).想象一下,这个有效载荷:
{ "age": "invalid" }
在这种情况下,我想要返回的是"错误"响应,例如:
{ "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", } ] }
解决这个问题的简单方法是简单地将"age"字段指定为"String"类型,然后在将值传递给持久层时将其转换.但是,我并不喜欢采用以全面方式使用字符串的数据传输对象的想法 - 在保留简洁设计方面这样做似乎是错误的.
我想到的另一个选择是创建一个类,如:
public abstract class BindableValue{ private String stringValue; private T value; public T getValue() { if(value == null) { value = fromString(stringValue); } return value; } protected abstract T fromString(String stringValue); }
然后,我可以创建诸如IntegerValue,LongValue,DateTimeValue等实现,当然也为Jackson编写自定义类型适配器.然后我的Person类可能是:
public class Person { @NotNull private StringValue firstname; @NotNull private StringValue surname; @Min(value = 0) private IntegerValue age; ... }
这几乎是我想要的,但不幸的是,@ NTNull和@Min等JSR-303注释不会识别我的BindableValue实现.
那么,任何人都能解释一种我能以更清洁的方式解决这个问题的方法吗?