53

Is it possible to validate a collection of objects in JSR 303 - Jave Bean Validation where the collection itself does not have any annotations but the elements contained within do?

For example, is it possible for this to result in a constraint violation due to a null name on the second person:

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);
Soumitri Pattnaik
  • 3,246
  • 4
  • 24
  • 42
cam
  • 681
  • 1
  • 6
  • 7

5 Answers5

71

Yes, just add @Valid to the collection.

Here is an example from the Hibernate Validator Reference.

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

This is standard JSR-303 behavior. See Section 3.1.3 of the spec.

sourcedelica
  • 23,940
  • 7
  • 66
  • 74
  • I assume that in this case the @NotNull validation will validate both that the that the list of pasengers is not null and that the Person in every element of the array is not Null. Won't it? – borjab Sep 16 '16 at 14:51
  • No... see https://stackoverflow.com/questions/27984137/java-beans-validation-collection-map-does-not-contain-nulls – Archie Aug 10 '17 at 19:54
22

You, can also add @NotEmpty to the collection.

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

this will ensure at least one passenger is present, and the @Valid annotation ensures that each Person object is validated

dezzer10
  • 752
  • 7
  • 9
4

As of Bean Validator 2.0, both of these approaches work:

class MyDto {

    private List<@Valid MyBean> beans;
}

and

class MyDto {

    @Valid
    private List<MyBean> beans;
}
M. Justin
  • 14,487
  • 7
  • 91
  • 130
Hamid Mohayeji
  • 3,977
  • 3
  • 43
  • 55
  • 1
    Is there any difference or at least a recommended way? I don't find it in hibernate validator documentation, looks like examples on their documentation use the first approach – Whimusical Apr 24 '20 at 15:36
  • @Whimusical — I don't think there's a difference with respect to `@Valid`. Annotations on generic type parameters was introduced in Java 8, and the older Bean Validation 1.2 annotations weren't set up to be attached to generic type parameters. This changed with Bean Validation 2.0/Hibernate 6 (and to a limited extent in Hibernate 5.2). I suspect for newer code, putting `@Valid` in the annotation itself is more idiomatic, since it's conceptually applying to each element of the collection. I go into this in more detail here: https://stackoverflow.com/a/33481403/1108305. – M. Justin Oct 01 '20 at 18:46
3

You can of course also just iterate over the list and call Validator.validate on each element. Or put the List into some wrapper bean and annotate it with @Valid. Extending ArrayList for validation seems wrong to me. Do you have a particular use case you want to solve with this? If so maybe you can explain it a little more. To answer your initial question:

Is it possible to validate a collection of objects in JSR 303 - Jave Bean Validation where the collection itself does not have any annotations but the elements contained within do?

No

Hardy
  • 18,659
  • 3
  • 49
  • 65
  • I'm using JAX-RS and have a json list of objects which i parse into a list of java beans. I don't have a wrapper object for the list, so no property to annotate... i thought that if this was going to be a general problem in not having a wrapping bean, instead of creating a new wrapper for each type of list it might be easier just to annotate a generic list subclass. I think this would also be achievable though with a generic wrapping bean as you suggest, eg: public class ValidatableListBean> { @Valid private T list; } – cam Nov 09 '10 at 10:23
  • Actually, maybe that class would look more like this: public class ValidatableBeanList { @Valid private List list; } – cam Nov 09 '10 at 10:29
  • ValidatableBeanList seems reasonable for your usecase. – Hardy Nov 10 '10 at 09:04
  • Has it changed in JSR 380? – Pavel_K Oct 09 '20 at 18:41
1

I wrote this generic class:

public class ValidListWrapper<T> {

    @Valid
    private List<T> list;

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

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

}

If you are using Jackson library to deserialize JSON you can add @JsonCreator annotation on the constructor and Jackson will automatically deserialize JSON array to wrapper object.

holmis83
  • 15,922
  • 5
  • 82
  • 83
  • Can you write a custom validator for List that will check if there are duplicate objects, by some property on those objects? Like...if multiple objects have same value at the property "name" – Alchnemesis Mar 17 '21 at 14:22