今天我很高兴宣布Hibernate Validator 5.0.0.Alpha2和4.3.1.Final同时发布。
Hibernate Validator 5
5.0.0.Alpha2版本与Bean Validation 1.1(1.1.0.Beta2)的公开审查草案同步。以下将更详细地介绍一些更改。
方法验证
用于验证方法参数和返回值的方法已从javax.validation.Validator移动到新的专用接口MethodValidator。它可以通过以下方式获得和使用:
MethodValidator methodValidator = Validation .buildDefaultValidatorFactory() .getValidator() .forMethods(); OrderService myOrderService = ...; Method placeOrderMethod = ...; Object[] arguments = ...; Set<ConstraintViolation<OrderService>> = methodValidator .validateParameters(myOrderService, placeOrderMethod, arguments);
与方法验证相关,现在支持跨参数约束。当需要一起验证方法或构造函数的多个参数时,这些约束非常有用,类似于传统的类级约束。以下是一个示例:
@ConsistentDateParameters public void createCalendarEvent(Date start, Date end) { //... }
与对单个参数的约束相反,跨参数约束是在方法本身上指定的。为了使您的代码的读者能够区分跨参数约束和返回值约束,建议选择一个明确表达约束目的的名称。
跨参数约束可以这样定义:
@Target({ METHOD, ANNOTATION_TYPE }) @Retention(RUNTIME) @CrossParameterConstraint(validatedBy = ConsistentDateParametersValidator.class) @Documented public @interface ConsistentDateParameters { String message() default "{ConsistentDateParameters.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
如您所见,这看起来与正常的Bean Validation约束注解非常相似。唯一的区别是使用@CrossParameterConstraint元注解来指定约束的验证器。验证器必须支持Object[]作为验证类型。
public class ConsistentDateParametersValidator implements ConstraintValidator<ConsistentDateParameters, Object[]> { @Override public void initialize(ConsistentDateParameters constraintAnnotation) { //nothing to do } @Override public boolean isValid(Object[] value, ConstraintValidatorContext context) { if ( value.length != 2 ) { throw new IllegalArgumentException( "Unexpected method signature" ); } if ( value[0] == null || value[1] == null ) { return true; } if ( !( value[0] instanceof Date ) || !( value[1] instanceof Date ) ) { throw new IllegalArgumentException( "Unexpected method signature" ); } return ( ( Date ) value[0] ).before( ( Date ) value[1] ); } }
由于此验证器在表示要验证的方法参数的对象数组上操作,因此必须首先检查参数的数量和类型。这种方法的优势是允许实现通用的跨参数约束,这些约束不特定于某个方法。
@AreEqual(indexes={0,1}, message="Passwords must be identical") public void resetPassword(String password, String confirmedPassword) { //... }
Bean Validation EG 还考虑了一种更安全的类型化方法,尽管它也有一些怪癖。请告诉我们哪种方法最适合您。
与 CDI 集成
Bean Validation 1.1 中的一个重要主题是与 CDI 的集成。5.0.0.Alpha2 版本提供了对此功能的初始支持。因此,现在可以通过 CDI 将依赖项注入到约束验证器实现中。
public class OrderNumberValidator implements ConstraintValidator<ValidOrderNumber, String> { @Inject private OrderValidationService orderValidationService; @Override public void initialize(ValidOrderNumber constraintAnnotation) { //nothing to do } @Override public boolean isValid(String value, ConstraintValidatorContext context) { return orderValidationService.isValid(value); } }
但这还不是全部。当在一个具有参数或返回值约束的 CDI 管理 bean 上调用方法时,会自动激活一个拦截器,该拦截器会验证参数和返回值。如果任一无效,将抛出 ConstraintViolationException 异常。这可以保护方法实现不受非法参数值的影响,并保护调用者不受非法返回值的影响。因此,您将再也不需要编写这样的代码了。
public void placeOrder(Item item, int quantity) { if(item == null) { throw new IllegalArgumentException("Item must not be null"); } if(quantity < 1) { throw new IllegalArgumentException("Quantity must be at least 1"); } //actual implementation }
相反,这样做就足够了
public void placeOrder(@NotNull Item item, @Min(1) int quantity) { //actual implementation }
这不仅简化了实现,还确保了调用者知道约束条件,因为它们是方法公共 API 的一部分。
组转换
最后,支持在级联验证期间转换已验证的组,这是一个Bean Validation规范中长期存在的功能请求。记住,当使用 @Valid 注解元素(例如属性或方法参数)时,验证将传播到引用的对象。
借助新的 ConvertGroup 注解,现在可以定义在父元素上给定组被验证时,级联元素上应验证哪个组或序列。让我们看一个例子。
//validation groups public interface Complete extends Default {} public interface BasicPostal {} public interface FullPostal extends BasicPostal {} public class Address { @NotNull(groups = BasicPostal.class) String street1; @NotNull String street2; @Size(groups = BasicPostal.class, min = 3) String zipCode = "12"; @Size(groups = FullPostal.class, max = 2) String doorCode = "ABC"; } public class User { @Valid @ConvertGroup.List({ @ConvertGroup(from = Default.class, to = BasicPostal.class), @ConvertGroup(from = Complete.class, to = FullPostal.class) }) Set<Address> addresses = new HashSet<>(); }
当使用默认组验证 User 对象时,对于相关地址,将验证 BasicPostal 组中的约束。当使用 Complete 组验证 User 对象时,这将导致验证用户地址上的 FullPostal 组中的约束。
此功能应有助于跨应用程序的不同层进行级联验证,这些层都定义了不同的验证组。
虽然这些都是此版本的主要更改,但还有一些值得注意的更改,例如对元数据 API 的一些修改,以及对 ConfigurationSource 的某些更改,以及一些错误修复。与Bean Validation 1.1 无关,我们完成了工作,以清楚地分离代码库的API、SPI和内部部分。变更日志包含了所有细节。
Hibernate Validator 4.3
虽然我们正在努力实现Bean Validation规范的修订版1.1,以便为Hibernate Validator 5开发,但我们决定为Bean Validation 1.0的参考实现Hibernate Validator 4.3发布一个维护版本。
我们修复了一些错误,最值得注意的是HV-591。这导致在将@Email约束应用于长字符串时出现错误。有趣的是,这是我们迄今为止在Hibernate Validator中报告的最多的问题,共有四个重复。我想知道谁会选择超过60个字符的电子邮件地址,但现在我们可以验证它了。:)请查看变更日志,以了解4.3.1中修复的所有问题的完整概述。
总结
本部分总结了我们对Hibernate Validator新版本发布的巡礼。
与往常一样,您可以从SourceForge获取这两个版本(4.3.1.Final,5.0.0.Alpha2)。Maven坐标分别为org.hibernate:hibernate-validator:4.3.1.Final和org.hibernate:hibernate-validator:5.0.0.Alpha2。欢迎您在论坛、问题追踪器和我们的邮件列表中提出反馈。由于新特性尚未在Hibernate Validator参考指南中描述,您可能对最新的规范草案感兴趣。
如果您对Bean Validation 1.1规范有任何想法或建议,请毫不犹豫地直接与专家小组进行交流。