Hibernate Validator:在验证集合本身之前验证集合项

问题描述 投票:0回答:1

问题:

我有一个正在由 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

通过上面的代码示例,我需要以下验证顺序:

  1. @ValidA
  2. @ValidB
  3. @field:ValidList

我的需求说明:

A
B
上的低级验证器必须确保对象
A
B
的隔离有效性,而顶级列表验证器必须相互验证列表的元素。

在验证列表中相对于彼此的元素时,每个单独的元素必须已经有效。否则,首先执行的列表验证将没有意义,并且如果列表的各个元素无效,可能会产生奇怪的无意义的违规。


Hibernate Validator 是否有可能实现这种行为?


我尝试使用

@GroupSequence
解决我的问题,但我无法确定如何在我的情况下正确使用它。

我还发现,当我在

@Valid
字段上方使用注释
List
时,Hibernate Validator 总是首先验证此
List
,然后才验证内部对象,但是如果我不使用
@Valid
并使用一些注释在集合的泛型中,如
List<@ValidSome BaseType
>,Hibernate Validator 在国内首先验证内部对象(正是我想要实现的),但在这种情况下,它忽略层次结构并且不验证
A
B
完全通过他们的注释。

java kotlin bean-validation hibernate-validator javax-validation
1个回答
0
投票

好吧,看来我已经解决了这个问题。事实上,验证组可以完成这项工作,幸运的是,即使不使用

@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
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.