JSR 303: How to Validate a Collection of annotated objects?
Asked Answered
B

5

52

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);
Bicyclic answered 5/11, 2010 at 14:25 Comment(0)
H
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.

Horned answered 21/8, 2011 at 3:32 Comment(2)
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?Shuttle
No... see #27984637Adp
A
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

Anthropomorphize answered 13/3, 2012 at 11:25 Comment(0)
A
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;
}
Artemisia answered 20/10, 2019 at 9:0 Comment(2)
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 approachArabela
@Arabela — 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://mcmap.net/q/354041/-java-beans-validation-collection-map-does-not-contain-nulls.Constructive
L
2

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

Lazuli answered 7/11, 2010 at 12:36 Comment(4)
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<T extends List<?>> { @Valid private T list; }Bicyclic
Actually, maybe that class would look more like this: public class ValidatableBeanList<T> { @Valid private List<T> list; }Bicyclic
ValidatableBeanList<T> seems reasonable for your usecase.Lazuli
Has it changed in JSR 380?Crifasi
A
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.

Apostasy answered 2/8, 2016 at 8:51 Comment(1)
Can you write a custom validator for List<T> 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"Phototypography

© 2022 - 2024 — McMap. All rights reserved.