JSR 303:如何验证一组带注释的对象?

53

在JSR 303 - Java Bean Validation中,是否可以验证一组对象,其中集合本身没有任何注释,但其内部包含的元素有注释?

例如,是否可能由于第二个人的名称为空而导致约束违规:

List<Person> people = new ArrayList<Person>();
people.add(new Person("dave"));
people.add(new Person(null));

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<List<Person>>> validation = validator.validate(people);
5个回答

71

可以的,只需将@Valid添加到集合中即可。

这里是Hibernate Validator参考文档中的一个示例

public class Car {
  @NotNull
  @Valid
  private List<Person> passengers = new ArrayList<Person>();
}

这是标准的JSR-303行为。请参见规范第3.1.3节。


我认为在这种情况下,@NotNull验证将同时验证乘客列表不为空以及数组中每个元素的Person对象不为空。是吗? - borjab
请参见 https://dev59.com/1obca4cB1Zd3GeqPcvdx,该链接讨论了Java Bean验证集合/Map不包含nulls的问题。 - Archie

22

你也可以向集合添加@NotEmpty

public class Car {
  @NotEmpty(message="At least one passenger is required")
  @Valid
  private List<Person> passengers = new ArrayList<Person>();
}

这将确保至少有一个乘客在场,而 @Valid 注释确保每个 Person 对象都经过了验证。


4
从 Bean Validator 2.0 开始,这两种方法都可以使用:
class MyDto {

    private List<@Valid MyBean> beans;
}

并且

class MyDto {

    @Valid
    private List<MyBean> beans;
}

1
有什么区别或至少推荐的方法吗?我在Hibernate验证器文档中没有找到它,看起来他们文档中的示例使用第一种方法。 - Whimusical
@Whimusical — 我认为与 @Valid 相关的没有什么区别。在Java 8中引入了通用类型参数的注释,而旧版本的Bean Validation 1.2注释并未设置为附加到通用类型参数。这在Bean Validation 2.0/Hibernate 6(在Hibernate 5.2中有一定程度上也是如此)中发生了变化。我怀疑对于新代码来说,在注释本身中放置 @Valid 更具语言习惯性,因为它的概念适用于集合的每个元素。我在这里详细说明了这一点:https://dev59.com/1obca4cB1Zd3GeqPcvdx#33481403。 - M. Justin

3
你当然也可以遍历列表并在每个元素上调用Validator.validate。或者将List放入某个包装器bean中,并用@Valid注释它。对我来说,为验证扩展ArrayList似乎是错误的。您有特定的用例要解决吗?如果是这样,也许您可以再解释一下。回答你最初的问题:不可以。

我正在使用JAX-RS,并有一个JSON对象列表,我将其解析为Java Bean列表。我没有列表的包装器对象,因此没有属性可供注释...我认为,如果这将是没有包装bean的一般问题,那么不是为每种类型的列表创建新的包装器,而是注释通用列表子类可能会更容易。我认为这也可以通过通用包装bean实现,例如:public class ValidatableListBean> { @Valid private T list; } - cam
实际上,也许这个类看起来更像这样:public class ValidatableBeanList { @Valid private List list; } - cam
ValidatableBeanList<T> 对于您的使用案例似乎很合理。 - Hardy
JSR 380有没有改变? - Pavel_K

1
我写了这个通用类:
public class ValidListWrapper<T> {

    @Valid
    private List<T> list;

    public ValidListWrapper(List<T> list) {
        this.list = list;
    }

    public List<T> getList() {
        return list;
    }

}

如果您正在使用Jackson库来反序列化JSON,您可以在构造函数上添加@JsonCreator注释,Jackson将自动将JSON数组反序列化为包装器对象。

你能否为List<T>编写一个自定义验证器,以检查是否存在重复对象,通过这些对象上的某个属性?比如...如果多个对象在属性“name”上具有相同的值。 - Alchnemesis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接