随着 Hibernate Validator 5.1.0.Alpha1 的发布,现在是时候继续 Bean Validation 1.1 焦点系列 并对方法验证进行探讨。长期使用 Hibernate Validator 的用户知道,方法验证自版本 4.2 以来就是验证器的一部分,但仅作为一个特定提供者的功能。Bean Validation 1.1 现在将方法验证纳入了 规范。
但什么是方法验证呢?方法验证是将约束注解放置到方法或构造函数及其参数上的能力。以下是一个示例
public class User {
public User(@NotNull @Size(max = 40) String firstName, @NotNull @Size(max = 40) String lastName) {
// ...
}
@NotNull
@Valid
public Order placeOrder(@NotNull @Valid Item item) {
// ...
}
@PasswordsMatch
public void resetPassword( @NotNull String password, @NotNull String passwordConfirmation) {
// ...
}
// ...
}
约束描述了每当调用User的构造函数时,firstName和lastName不能为null并且长度也不能超过40个字符。此外,每当用户下订单时,提供的Item实例不能为null并且必须是有效的。在这里,有效意味着实例本身通过所有其属性(字段和getter上的约束)和类级别的约束的验证。调用placeOrder()的方法返回的Order实例是一个非null实例,它也通过此类类型的所有bean约束。最后但并非最不重要的是,如果用户重置他的密码,新密码和密码确认不能为nullnull并且它们必须匹配。后者通过所谓的交叉参数约束 -.
@PasswordMatch
但是,这些约束如何得到验证呢?Bean Validation为此目的提供了ExecutableValidator,可以从Validator实例中通过Validator.forExecutables()获取。这ExecutableValidator提供了方法来验证方法/构造函数参数和返回值。然而,这本身对应用程序开发者并没有很大帮助。她必须自己编写必要的代码来处理验证,这不是一个简单任务。相反,目的是通过某种形式的AOP、拦截器或代理方法,由框架和库为应用程序开发者提供集成。这样,在调用受约束的方法或构造函数时,会透明地执行方法验证,当违反一个或多个约束时抛出ConstraintViolationException。此类集成的示例是Java EE 7框架。
在Java EE 7中,所有CDI管理豆都会自动进行方法验证。你所要做的只是将约束放置在方法或构造函数及其参数上。然后,CDI将通过其拦截器功能评估所有方法验证约束。在此背景下,了解Bean Validation默认不验证getter(方法名以get开头,有返回类型且无参数,或以is开头,返回boolean且无参数)非常重要。这是为了避免与bean约束的验证冲突。此行为可以通过使用@ValidateOnExecution或在validation.xml中使用default-validated-executable-types进行配置。规范包含了所有细节,并给出了一些示例。
最后但并非最不重要的是,另一个注意事项。当在类层次结构中使用方法验证约束时,规范要求必须遵守Liskov替换原则。正式地说,这意味着方法的前置条件(由参数约束表示)不得加强,后置条件(由返回值约束表示)不得减弱在子类型中。具体而言,这意味着在子类型中不能在重写或实现的方法上声明参数约束。此外,参数也不能标记为级联验证。相反,所有参数约束必须在层次结构中方法的根处定义。如果违反了Liskov替换原则,Bean Validation实现将抛出ConstraintDeclarationException。完整的规则可以在规范的继承层次结构中的方法约束部分中找到。
我希望这篇博客能帮助您了解Bean Validation 1.1最大的新特性——方法验证。如果您有任何问题,请留下评论,通过论坛联系我们,或在IRC中与我们聊天。
祝您验证愉快!
附言:我们将在另一篇文章中讨论与方法验证相关的元数据和javax.validation.PathAPI的变化。我们还将更详细地了解实现跨参数约束的细节。请保持关注。