Hibernate Validator

常见问题解答

一般

Hibernate Validator 3、4 和 5 之间的区别是什么?

Hibernate Validator 3.x 和 4.x/5.x 是不同的代码库。

Hibernate Validator 是来自 Hibernate 团队的原始验证框架,现在被称为“Legacy Hibernate Validator”。Hibernate Validator 4.x 是 Bean Validation 1.0 (JSR 303) 的参考实现,而 Hibernate Validator 5.x 是 Bean Validation 1.1 (JSR 349) 的参考实现。积极的开发发生在 5.x 代码库上。

为什么当我在调用 persist() 时,我的 JPA 实体没有经过验证?

简短的回答是,如果您想触发验证,请调用 EntityManager#flush()

Hibernate ORM 和其他一些 ORM 尝试在访问数据库时尽可能地批量执行操作。当您调用 flush() 或事务提交时,实体的实际“persist”操作很可能才会发生。

此外,确定即将持久化的实体取决于您的级联策略和对象图的状态。Flush 是 Hibernate ORM 识别所有已更改并需要数据库操作的实体的时候(另见 HHH-8028)。

我的问题没有得到解答。在哪里可以找到帮助?

查看参考指南,其中详细介绍了Hibernate Validator的所有细节。如果指南没有回答您的问题,请访问论坛,您将在那里得到帮助。

兼容性

Hibernate Validator 5.x 是否支持 Tomcat 6?

支持,如果您更新 Tomcat 的 EL 库。

Hibernate Validator 5 需要版本 2.2 或更高版本的统一表达式语言 (EL)。虽然 Tomcat 7 默认提供 EL 2.2,但 Tomcat 6 仅附带 EL 2.1 实现,该实现与 Hibernate Validator 不兼容。您将得到

NoSuchMethodError: javax.el.ExpressionFactory.newInstance()Ljavax/el/ExpressionFactory)

因此,您可以升级到 Tomcat 7 或更新 Tomcat 6 安装中的 EL 库。要执行后者,请使用 EL 2.2 实现(例如,来自 Tomcat 7)替换 $CATALINE_HOME/lib 中的 JAR 文件 el-api.jar 和 jasper-el.jar。

请注意,仅仅将 EL 2.2 实现添加到您的 WAR 并保留 Tomcat 自身的 EL 2.1 实现是不够的。在这种情况下,两个版本将发生冲突,通常由一个 LinkageError 表示,该错误表明 ExpressionFactory 类已由不同的类加载器加载了两次。

约束

如何检查我的 Bean 中的两个字段是否具有相同的值?

通过实现类级约束

如何在 ConstraintValidator 中访问 Hibernate Session 或 EntityManager?

参见此示例

我可以在运行时动态声明约束吗?

此 Hibernate Validator 特定 API 很有用,例如,如果您需要根据某些运行时配置调整约束参数,或者处理多租户环境,在这种环境中,应根据特定租户对给定类型应用不同的约束。

要使用此 API,请从 HibernateValidatorConfiguration 获取一个 ConstraintMapping,根据需要对其进行配置,然后将其传递回配置

HibernateValidatorConfiguration configuration = Validation
        .byProvider( HibernateValidator.class )
        .configure();

ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
    .type( Address.class )
        .property( "street1", FIELD )
            .constraint( new NotNullDef() )
        .property( "zipCode", FIELD )
            .ignoreAnnotations()
            .constraint( new NotNullDef() )
            .constraint( new SizeDef().min( 2 ).max( 6 ) );

Validator validator = configuration.addMapping( constraintMapping )
        .buildValidatorFactory()
        .getValidator();

如何找出为给定类或属性声明了哪些约束?

您可以使用约束元数据 API

借助元数据 API,您可以例如实现一个通过 REST 导出约束信息的解决方案,从而允许使用 JavaScript 进行客户端验证。下一个问题显示了一个使用该 API 的示例。

使用元数据 API 是否可以确定给定约束是在字段级别还是属性级别指定的?

可以。

PropertyDescriptor property =
    validator.getConstraintsForClass(Address.class)
               .getConstraintsForProperty("street1");

Set<ConstraintDescriptor<?>> fieldConstraints =
    property
        .findConstraints()
            .lookingAt(Scope.LOCAL_ELEMENT)
            .declaredOn(ElementType.FIELD)
            .getConstraintDescriptors();

Set<ConstraintDescriptor<?>> propertyConstraints =
    property
        .findConstraints()
            .lookingAt(Scope.LOCAL_ELEMENT)
            .declaredOn(ElementType.METHOD)
            .getConstraintDescriptors();
The key is the use of the +findConstraints()+ fluent API. You have three ways to restrict the metadata:
  • declaredOn(ElementType... types):定义在何处查找约束(METHOD、FIELD 等)

  • lookingAt(Scope scope):定义是否查找托管在超类/接口上的约束

  • unorderedAndMatchingGroups(Class<?>... groups):将约束限制为与该元素给定组集匹配的约束

错误

使用 HV 注解处理器时,出现类似“类型不兼容,找到:XY,要求:XY”的编译错误,是什么问题?

这是由 javac 编译器中的错误导致的,当编译的项目包含一个带有枚举类型成员的注解类型,并且该成员具有默认值时,就会发生这种情况。作为解决方法,可以使用其完全限定名指定默认值,或者将此注解处理器添加到您的项目中。有关更多详细信息,另请参见HV-498

如何避免错误“HV000150:约束'javax.validation.constraints.DecimalMin'为类型'interface javax.money.MonetaryAmount'定义了多个验证器。只允许一个。”?

如果您在类路径上有org.zalando:money-validation依赖项,您将在 Hibernate Validator 5.4 及更高版本中遇到此错误。money-validation 项目已贡献给 Hibernate Validator 代码库,即 Hibernate Validator 允许开箱即用地验证MonetaryAmount。从类路径中删除money-validation依赖项,以避免与现在内置于 Hibernate Validator 的约束验证器发生冲突。

返回顶部