一般
为什么当我在调用 persist() 时,我的 JPA 实体没有经过验证?
简短的回答是,如果您想触发验证,请调用 EntityManager#flush()
。
Hibernate ORM 和其他一些 ORM 尝试在访问数据库时尽可能地批量执行操作。当您调用 flush()
或事务提交时,实体的实际“persist”操作很可能才会发生。
此外,确定即将持久化的实体取决于您的级联策略和对象图的状态。Flush 是 Hibernate ORM 识别所有已更改并需要数据库操作的实体的时候(另见 HHH-8028)。
兼容性
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?
参见此示例。
我可以在运行时动态声明约束吗?
可以,使用用于程序性约束声明的 API。
此 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):将约束限制为与该元素给定组集匹配的约束
错误
如何避免错误“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 的约束验证器发生冲突。