How to use Java Bean Validators (JSR-303/JSR-349) on elements of an array/list/collection
Asked Answered
L

4

8

I'm new to using Java Bean validation (JSR-303/JSR-349/Hibernate Validator), and understand the general concepts. However, I'm not sure how to validate the contents of an composed type vs the type itself.

For example:

@NotNull
private List<String> myString;

will validate that the List myString is not null, but does nothing for validating the contents of the list itself. Or given other types of validators (Min/Max/etc), how do I validate the individual elements of the List? Is there a generic solution for any composed type?

Lanettelaney answered 4/12, 2013 at 19:37 Comment(0)
C
5

There is no easy generic solution as of Bean Validation 1.0/1.1. You could implement a custom constraint like @NoNullElements:

@NoNullElements
private List<String> myStrings;

The constraint's validator would iterate over the list and check that no element is null. Another approach is to wrap your String into a more domain-specific type:

public class EmailAddress {

    @NotNull
    @Email
    private String value;

    //...
}

And apply cascaded validation to the list via @Valid:

@Valid
private List<EmailAddress> addresses;

Having such a domain-specific data type is often helpful anyways to convey a data element's meaning as it is passed through an application.

In the future a generic solution for the issue may be to use annotations on type parameters as supported by Java 8 but that's only an idea at this point:

private List<@NotNull String> myStrings;
Chyle answered 4/12, 2013 at 21:42 Comment(2)
Thanks! That's pretty much what I had come up with as well, however I was hoping that there would have been built-in support for aggregate constructs, but apparently that is missing.Lanettelaney
List<@NotNull String> is supported as a proprietary feature in recent versions of Hibernate Validator 5.x and will be official part of the Bean Validation 2.0 spec.Chyle
T
2

Take a look at validator-collection – it’s very easy to use any Constraint Annotation on a collection of simple types with this library. Also see https://mcmap.net/q/138841/-hibernate-validation-of-collections-of-primitives.

Triplicity answered 3/1, 2014 at 20:18 Comment(1)
Thanks for sharing. Will definitely take a closer look at it, but looks promising.Lanettelaney
G
0

Upcoming jsr 380 (bean validation 2.0) will allow to put constraints annotation to argument type.

@Valid private List<@NotNull String> myString;

For now Bean Validation 1.1 in you can create custom constraints that checks null condition.

Glossal answered 16/6, 2017 at 19:8 Comment(1)
You don't need the @Valid annotation here; when the type containing myString(s) is validated, the elements of that list will be validated too and the @NotNull constraint be applied to each of them.Chyle
A
0

Bean Validation 2.0/Hibernate Validator 6.0

Bean Validation 2.0 (of which Hibernate Validator 6.0 is the reference implementation) allows using its validation annotations directly on generic type arguments. This is noted in the Hibernate 6.0 release documentation:

Hibernate Validator 6.0 is the Reference Implementation of the Bean Validation 2.0 specification so it comes with all its new features:

  • First class support of container element constraints and cascaded validation (think private Map<@Valid @NotNull OrderCategory, List<@Valid @NotNull Order>> orderByCategories;);

If the project is using Java 8 with Bean Validation 2.0, this feature can be used to validate each element of the list:

private List<@NotNull String> myString; // Validate that none of the list items is null

Bean Validation 1.2/Hibernate Validator 5.2

Hibernate 5.2 (with Bean Validation 1.2) added a limited version of the feature to allow validation annotations directly on generic type arguments. However, none of its built-in Bean Validation or Hibernate Validation constraints could be used in this manner, as the annotations do not specify ElementType.TYPE_USE for backwards-compatibility reasons. Additionally, type argument constraints could be specified for map values but not map keys. This is all described in the Hibernate Validator 5.2 documentation:

Starting from Java 8, it is possible to specify constraints directly on the type argument of a parameterized type. However, this requires that ElementType.TYPE_USE is specified via @Target in the constraint definition. To maintain backwards compatibility, built-in Bean Validation as well as Hibernate Validator specific constraints do not yet specify ElementType.TYPE_USE.

[...]

When applying constraints on an Iterable type argument, Hibernate Validator will validate each element.

[...]

Type argument constraints are also validated for map values. Constraints on the key are ignored.

Summary

In summary, if the code is using Java 8 with Bean Validation 2.0 (such as Hibernate Validator 6), the generic list & map type arguments can be annotated:

private List<@NotNull String> myString;

If the code is using Java 8 with Bean Validation 1.2 and Hibernate Validator 5.2, custom validation annotations can be written with TYPE_USE in its definition, and applied to the generic type of the collection or map value:

private List<@MyCustomNotNull String> myString;

If the code is not using Java 8 or is on a version of Hibernate Validator prior to 5.2, a custom constraint could be written which verifies every element of a collection or map and applied to the collection or map itself.

@MyCustomNotNullElements
private List<String> myString;
Abdulabdulla answered 19/1, 2021 at 8:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.