В этой статье, посвящённой Jakarta Bean Validation, будет подробно рассмотрен процесс валидации объектов: применение ограничений к элементам классов, их валидация, а также валидация записей (record
).
Цикл статей о Jakarta Bean Validation
Данная статья является частью цикла статей о Jakarta Bean Validation:
- Знакомство с Jakarta Bean Validation 3.0
- Валидация объектов (Вы сейчас её читаете)
- Валидация методов
- Группы валидации (В процессе написания)
- Создание ограничения и валидатора (В процессе написания)
- Интерполяция сообщений (В процессе написания)
- Конфигурация валидатора (В процессе написания)
Ограничения
В рамках классов ограничения могут применяться к полям, свойствам и самим классам. Кроме этого ограничения суммируются при наследовании.
Ограничение поля
При работе с объектами возможна валидация полей и свойств классов, конкретных значений и объектов целиком. Примеры применения ограничений ниже будут продемонстрированы ниже при помощи аннотаций и XML, использовать одновременно и аннотации, и XML не нужно, старайтесь выбрать какой-то один подход, наиболее удобный для вас.
При использовании ограничения поля аннотация ограничения указывается непосредственно у объявленного поля класса:
При помощи аннотации @Min
задано ограничение, согласно которому значение поля age
не должно быть меньше 18, про данное ограничение более подробно будет написано ниже в этой статье.
В XML ограничения полей задаются в блоке <field>
:
Ограничение свойства
Если класс соответствует спецификации Java Beans, то ограничение можно применить к методу get..
:
Применение аннотаций ограничений к get…
-методам может вызывать некоторую путаницу, так как применение аннотаций ограничений к возвращаемым значениям методов и аннотаций перекрёстных ограничений к аргументам методов выглядит схожим образом, что будет показано ниже.
В XML ограничение свойства задаётся в блоке <getter>
и не вызывает такой путаницы:
Ограничение класса
Jakarta Bean Validation предоставляет возможность использования ограничений для классов. Это может быть полезным, когда используется какая-то сложная логика валидации, зависящая от значений свойств объекта.
Каких-то стандартных ограничений для классов спецификация не предоставляет.
Ограничение класса задаётся аннотацией для валидируемого класса:
То же самое может быть реализовано в XML при помощи <class>
:
@ValidCandidate
— это собственное ограничение. Создание и использование собственных ограничений будет рассмотрено в отдельной статье.
Ограничение элементов контейнера
Jakarta Bean Validation позволяет задавать ограничения для объектов, находящихся в контейнерах. Поддерживаются следующие виды контейнеров:
- Наследники и реализации
java.util.Iterable
, включаяList
,Set
,Queue
и т.д. - Наследники и реализации
java.util.Map
java.util.Optional
и родственные классы- И некоторые другие
Для использования ограничения к элементам контейнеров аннотацию нужно добавить к типу обобщения (дженерика) контейнера:
Ограничение @NotNull
указывает на то, что объект не должен быть null
.
Применение аннотации ограничения к типу обобщения возможно благодаря значению ElementType.TYPE_USE
в @Target
.
Ограничения элементов контейнеров могут быть установлены в XML при помощи <container-element-type>
следующим образом:
Валидируемый контейнер может быть любым элементом, который можно провалидировать: свойством класса, аргументом метода или конструктора или возвращаемым значением метода.
Наследование ограничений
Применяемые к элементам классов и интерфейсов ограничения сохраняются при использовании наследования и распространяются на дочерние типы. Наследники в свою очередь могут добавлять собственные ограничения.
Допустим, в проекте есть интерфейс OrderDomainEvent
:
а так же класс AbstractOrderDomainEvent
:
и класс OrderCreated
:
Класс OrderCreated
в дополнение к собственным ограничениям унаследует ограничения, объявленные в OrderDomainEvent
и AbstractOrderDomainEvent
.
Особенности записей (record
)
В JDK 16 появился новый тип классов — запись (record
), который может применяться для описания объектов передачи данных (Data transfer object; DTO).
Ограничения можно применять к элементам записей, ровно, как и валидировать их.
Пример применения ограничений к записи:
Особенности применения ограничений к элементам записи при помощи аннотаций:
- Ограничение, указанное для класса (
@ValidCandidate
), применяется не только к классу, но и к конструктору - Ограничения свойств применяются так же к аргументам главного конструктора и методам, возвращающим значения свойств
В XML можно применять ограничения индивидуально к элементам записей.
Идентичный набор ограничений для обычного класса выглядел бы следующим образом:
Валидация
При работе с классами возможна валидация объектов целиком, отдельных их свойств, а также значений на основе правил валидации свойств классов.
Валидация объектов
Валидация объектов выполняется при помощи метода Validator.validate()
, который принимает два аргумента:
- Валидируемый объект
- Список групп валидации, который может быть пустым (здесь и далее будет применяться
jakarta.validation.groups.Default
, хоть явное указание этой группы и не требуется)
Результатом валидации является множество экземпляров ConstraintViolation
, описывающих ошибки валидации. В случае успеха метод validate
должен вернуть пустое множество.
Валидация свойств объекта
Jakarta Bean Validation предоставляет возможность валидации конкретных свойств объектов, для этого может быть использован метод validateProperty
, который принимает следующие аргументы:
- Валидируемый объект
- Название валидируемого свойства
- Список групп валидации
Данный метод, так же как и validate
, возвращает множество ошибок валидации в случае несоответствия значений правилам валидации.
Валидация значений
Так же есть метод validateValue
, позволяющий валидировать значения. При его помощи можно провести валидацию значения до присвоения свойству, т.е. провести превалидацию. При этом правила валидации, объявленные для указанного свойства валидируемого класса, будут применены к валидируемому значению. Данный метод принимает четыре аргумента:
- Класс валидируемого объекта
- Название валидируемого свойства
- Валидируемое значение
- Список групп валидации
Каскадирование валидации
По умолчанию валидация применяется только к валидируемому объекту, в то время как валидация вложенных объектов не производится. Если при валидации объекта требуется провалидировать и вложенные объекты, то такие объекты должны быть отмечены аннотацией @Valid
:
То же самое может быть достигнуто при помощи <valid>
в XML:
При валидации экземпляра CandidatesGroup
будет проведена проверка, что свойство candidates
не является null
, а также, что все элементы этого списка — тоже валидные объекты. Если хотя бы один элемент списка candidates
нарушает ограничения, то валидация завершится ошибкой.