@Valid
是 JSR-303 注释,JSR-303 适用于 JavaBeans 上的验证。A 不是 JavaBean(根据 JavaBean 的官方描述),因此不能使用符合 JSR-303 的验证器直接对其进行验证。这得到了两个观察结果的支持。java.util.List
JSR-303 规范的第 3.1.3 节规定:
除了支持实例验证外,还支持对象图形的验证。图形验证的结果作为一组统一的约束冲突返回。考虑以下情况:Bean X 包含类型为 Y 的字段。通过使用@Valid注释对字段 Y 进行批注,验证程序将在验证 X 时验证 Y(及其属性)。在 Y 类型(子类、实现)声明的字段中包含的值的确切类型 Z 是在运行时确定的。使用 Z 的约束定义。这可确保标记为@Valid的关联具有正确的多态行为。
集合值、数组值和通常可迭代的字段和属性也可以使用@Valid注释进行修饰。这将导致验证迭代器的内容。支持任何实现java.lang.Iterable的对象。
我以粗体标记了重要的信息。本节意味着,为了验证集合类型,必须将其封装在 Bean 中(由 );此外,集合不能直接验证(由 暗示,重点是字段和属性)。Consider the situation where bean X contains a field of type Y
Collection-valued, array-valued and generally Iterable fields and properties may also be decorated
实际的 JSR-303 实现
我有一个示例应用程序,它使用Hibernate Validator和Apache Beans Validator测试集合验证。如果以(使用休眠验证程序)和(对于 Bean Validator)对此示例运行测试,则两者都拒绝直接验证集合,这似乎符合规范。由于 Hibernate Validator 是 JSR-303 的参考实现,因此此示例进一步证明了集合需要封装在 Bean 中才能进行验证。mvn clean test -Phibernate
mvn clean test -Papache
清除了这一点后,我会说尝试以问题中所示的方式将集合直接传递给控制器方法也存在设计问题。即使验证直接在集合上工作,控制器方法也无法使用备用数据表示形式,例如自定义XML,SOAP,ATOM,EDI,Google协议缓冲区等,这些表示形式不会直接映射到集合。为了支持这些表示形式,控制器必须接受并返回对象实例。这需要以任何方式将集合封装在对象实例中。因此,非常建议像其他答案所建议的那样将另一个对象包裹在另一个对象内部。List