我有一个正在由 Hibernate 验证器验证的 bean。
该 bean 有一个
List
类型的属性,并且该属性具有自定义验证器 (1)。这个 List
的元素也有自己的自定义验证器 (2)。
我需要首先验证此列表的元素,只有在确保所有列表元素的有效性后,才必须验证整个列表。
困难还在于列表是多态的并且包含不同类型的元素,所有元素都是一个基本类型的后代,并且每个后代都有自己的自定义验证器。
下面的代码示例(简化):
// Validation root
class Bean(
// List validator (1)
@field:ValidList
val list: List<BaseType>
)
// Base type for list elements (has no validator)
interface BaseType
// Descendant 1 of the BaseType with custom validator (2.1)
@ValidA
class A : BaseType
// Descendant 2 of the BaseType with custom validator (2.2)
@ValidB
class B : BaseType
通过上面的代码示例,我需要以下验证顺序:
@ValidA
@ValidB
@field:ValidList
类
A
和 B
上的低级验证器必须确保对象 A
和 B
的隔离有效性,而顶级列表验证器必须相互验证列表的元素。
在验证列表中相对于彼此的元素时,每个单独的元素必须已经有效。否则,首先执行的列表验证将没有意义,并且如果列表的各个元素无效,可能会产生奇怪的无意义的违规。
Hibernate Validator 是否有可能实现这种行为?
我尝试使用
@GroupSequence
解决我的问题,但我无法确定如何在我的情况下正确使用它。
我还发现,当我在
@Valid
字段上方使用注释 List
时,Hibernate Validator 总是首先验证此 List
,然后才验证内部对象,但是如果我不使用 @Valid
并使用一些注释在集合的泛型中,如 List<@ValidSome BaseType
>,Hibernate Validator 在国内首先验证内部对象(正是我想要实现的),但在这种情况下,它忽略层次结构并且不验证 A
和 B
完全通过他们的注释。
好吧,看来我已经解决了这个问题。事实上,验证组可以完成这项工作,幸运的是,即使不使用
@GroupSequence
。
我创建了许多验证组接口,并定义了 Hibernate Validator 必须验证我的 bean 所需的顺序。然后我将我的组按照相应的申请顺序放入注释中。之后,剩下要做的就是循环遍历有序组列表,并分别对每个组调用 Hibernate Validator(检查下一组的验证是否失败,如果失败则中断循环)。
验证注释中的组定义及其用法:
object ValidationGroups {
interface BeanClass
interface BeanCollection
val allOrdered = listOf(
// 1. default group placed first to validate bean by annotations
// that are defined without groups at all, such as simple
// @Positive or @NotEmpty on some plain property
javax.validation.groups.Default::class,
// 2. then the bean class level validators must be invoked (only if
// all the properties of this bean validated by Default group are valid)
BeanClass::class,
// 3. after all, if the bean is valid by their class level validator,
// invoking validators on the outer collection property level
BeanCollection::class,
)
}
class Bean(
@field:ValidList(groups = [ValidationGroups.BeanCollection::class]) // 3. validated last
val list: List<BaseType>
)
interface BaseType
@ValidA(groups = [ValidationGroups.BeanClass::class]) // 2. validated second
class A : BaseType {
@field:Positive // 1. validated first
val id: Int
}
@ValidB(groups = [ValidationGroups.BeanClass::class]) // 2. validated second
class B : BaseType {
@field:NotEmpty // 1. validated first
val name: String
}
以及 Hibernate Validator 调用:
for (group in ValidationGroups.allOrdered) {
val violations = validator.validate(bean, group.java)
if (violations.isNotEmpty()) {
return violations
}
}