Jakarta Bean Validation — это спецификация, описывающая API для валидации объектов в рамках Jakarta EE. Вы можете использовать данную спецификацию для валидации в проектах вне зависимости от используемого фреймворка или сервера приложений. Более того, вы можете использовать Jakarta Bean Validation в полностью самостоятельных проектах, не основанных на Jakarta EE или каком-либо фреймворке.
Идейным предшественником Jakarta Bean Validation 3.0 является Bean Validation 2.0 из Java EE, однако все изменения в спецификации заключаются в переименованиях, связанных с миграцией проекта из Java EE в Jakarta EE.
В рамках этой статьи будет рассмотрен минимальный набор зависимостей, необходимый для использования Jakarta Bean Validation, описаны основные интерфейсы и ограничения или правила валидации.
Цикл статей о Jakarta Bean Validation
Данная статья является частью цикла статей о Jakarta Bean Validation:
- Знакомство с Jakarta Bean Validation 3.0 (Вы сейчас её читаете)
- Валидация объектов
- Валидация методов
- Группы валидации (В процессе написания)
- Создание ограничения и валидатора (В процессе написания)
- Интерполяция сообщений (В процессе написания)
- Конфигурация валидатора (В процессе написания)
Зависимости
Основной зависимостью является библиотека jakarta.validation:jakarta.validation-api, актуальная версия которой на момент написания статьи — 3.0.2. Добавлять данную библиотеку в зависимости проекта, как правило, не нужно — если ваш проект использует Jakarta EE API, то Bean Validation уже включён в зависимости. В остальных случаях данная библиотека будет являться транзитивной зависимостью библиотек, реализующих Bean Validation (например, org.hibernate.validator:hibernate-validator), либо библиотек зависящих от реализаций (например, org.springframework.boot:spring-boot-starter-validation).
Для примеров кода в рамках данной статьи я буду использовать Hibernate Validator 8.0.1.Final:
Основные типы Jakarta Bean Validation
Основные интерфейсы, с которыми вам предстоит взаимодействовать при использовании Jakarta Bean Validation: Validator, ExecutableValidator, ConstraintViolation и ConstraintValidator.
Validator
Интерфейс Validator используется для валидации объектов. Этот интерфейс объявляет следующие методы:
validate— для валидации объектовvalidateProperty— для валидации отдельного свойства объектаvalidateValue— для валидации значения относительно ограничений какого-либо свойства классаgetConstraintsForClass— для получения ограничений классаunwrap— для получения экземпляра класса, специфичного для конкретной реализации Jakarta Bean ValidationforExecutables— для получения экземпляраExecutableValidator, валидатора для методов
Создать валидатор можно одним из трёх способов:
ExecutableValidator
ExecutableValidator используется для валидации аргументов и возвращаемых значений методов и конструкторов. Он объявляет четыре метода:
validateParameters— для валидации аргументов методаvalidateConstructorParameters— для валидации аргументов конструктораvalidateReturnValue— для валидации значения, возвращённого методомvalidateConstructorReturnValue— для валидации значения, возвращённого конструктором
Получить экземпляр ExecutableValidator можно при помощи метода Validator.forExecutables():
ConstraintViolation
Все методы валидации возвращают множество экземпляров ConstraintViolation. Этот интерфейс описывает ошибку валидации и объявляет следующие методы:
getMessage()— для получения интерполированного сообщенияgetMessageTemplate()— для получения исходного шаблона сообщенияgetRootBean()— для получения валидируемого объектаgetRootBeanClass()— для получения класса валидируемого объектаgetLeafBean()— для получения объекта, в котором возникла ошибка валидацииgetExecutableParameters()— для получения аргументов валидируемого методаgetExecutableReturnValue()— для получения возвращаемого значения валидируемого методаgetPropertyPath()— для получения пути валидируемого свойстваgetInvalidValue()— для получения значения, не прошедшего валидациюgetConstraintDescriptor()— для получения дескриптора ограничения, которое было нарушеноunwrap()— для получения более конкретной реализацииConstraintViolation, специфичной для провайдера
Пример получения отчёта об ошибках валидации:
ConstraintValidator
Интерфейс ConstraintValidator используется для реализации логики конкретных правил валидации и объявляет два метода:
initialize— для инициализации, в ходе которой можно получить доступ аннотации ограниченияisValid— непосредственно для реализации логики валидации.
Пример реализации ConstraintValidator для ограничения jakarta.validation.constraints.NotNull:
Ограничения или правила валидации
Ограничение (constraint) — это правило валидации, описываемое специфичной для Jakarta Bean Validation аннотацией. Ограничение может применяться использованием аннотаций в коде, либо при помощи XML.
Типичная аннотация ограничения имеет следующий вид:
Аннотация @Target задаёт список элементов, к которым аннотация ограничения может быть применена. Данный список может отличаться от продемонстрированного.
@Retention задаёт вариант доступности аннотации при компиляции исходного кода, значение RUNTIME указывает на доступность аннотации во время исполнения.
Если аннотация ограничения должна иметь возможность применения несколько раз к элементу кода, то в значении аннотации @Repeatable необходимо указать имя класса-аннотации, описывающего множественное применение. При этом описывающая множественное применение аннотация должна иметь @Target и @Retention идентичные у описываемой аннотации.
Аннотация @Documented указывает на то, что описываемая аннотация будучи применённой к элементам кода будет являться частью публичного контракта.
При помощи аннотации @Constraint можно задать список классов, валидирующих элементы кода, отмеченные описываемой аннотацией.
Аннотация ограничения должна иметь как минимум три стандартных свойства:
String message, содержащее шаблон сообщения, который будет использован в случае нарушения ограниченияClass<?>[] groups, содержащее список типов для группировки ограничений при валидацииClass<? extends Payload>[] payload, содержащее список типов полезной нагрузки. Данное свойство может использоваться для передачи каких-то дополнительных данных в класс-валидатор.
Кроме этих свойств класс-аннотация ограничения может содержать свойство ConstraintTarget validationAppliesTo() со значением по умолчанию ConstraintTarget.IMPLICIT, данное свойство используется для ограничений, применимых к методам и конструкторам во избежание неоднозначности объекта валидации.
Стандартные ограничения
Jakarta Bean Validation предоставляет набор стандартных ограничений, который вы можете использовать в своих проектах.
@AssertFalse
Применяется к свойствам типов java.lang.Boolean и boolean, ограничивает валидируемое значение значением false.
@AssertTrue
Аннотация, аналогичная предыдущей, применяется также к свойствам типов java.lang.Boolean и boolean, но ограничивает валидируемое значение значением true.
@DecimalMax(value=, inclusive=)
Аннотация, применяемая к свойствам типов, представляющих целые числа:
BigDecimalBigIntegerCharSequencebyte,short,int,longи их классы-обёртки
Обратите внимание на то, что float и double, а так же их классы-обёртки не поддерживаются ввиду особенностей округления.
Свойством value задаётся максимальное значение валидируемого свойства, а inclusive — включается ли максимально значение в диапазон допустимых значений.
@DecimalMin(value=, inclusive=)
Аналогичная предыдущей аннотация, также применяемая к свойствам типов, представляющих целые числа:
BigDecimalBigIntegerCharSequencebyte,short,int,longи их классы-обёртки
double и float не поддерживаются.
Свойством value задаётся минимальное значение валидируемого свойства, а inclusive — включается ли минимальное значение в диапазон допустимых значений.
@Digits(integer=, fraction=)
Аннотация, при помощи которой можно ограничить максимальное количество знаков в целой и дробной части числа.
Как и предыдущие два ограничения поддерживает типы:
BigDecimalBigIntegerCharSequencebyte,short,int,longи их классы-обёртки
Типы double и float не поддерживаются.
Свойство integer задаёт максимальное количество знаков целой части числа, fraction — дробной.
@Email
Аннотация, применяемая к свойствам типа CharSequence и его наследников (String), требующая, чтобы валидируемая строка была валидным адресом электронной почты.
@Future
Аннотация, ограничивающая значение свойства будущим временем.
Поддерживаемые типы валидируемых свойств:
java.util.Datejava.util.Calendarjava.time.Instantjava.time.LocalDatejava.time.LocalDateTimejava.time.LocalTimejava.time.MonthDayjava.time.OffsetDateTimejava.time.OffsetTimejava.time.Yearjava.time.YearMonthjava.time.ZonedDateTimejava.time.chrono.HijrahDatejava.time.chrono.JapaneseDatejava.time.chrono.MinguoDatejava.time.chrono.ThaiBuddhistDate
@FutureOrPresent
Аннотация, ограничивающая значение свойства будущим или настоящим временем.
Список поддерживаемых типов идентичен таковому у @Future.
@Max(value=)
Аннотация, позволяющая указать максимальное значение свойства числового типа.
Поддерживаемые типы:
BigDecimalBigIntegerCharSequencebyte,short,int,longи их классы-обёртки
double и float не поддерживаются.
@Min(value=)
Аннотация, позволяющая указать минимальное значение свойства числового типа.
Список поддерживаемых типов идентичен таковому у @Max.
@NotBlank
Аннотация, требующая, чтобы валидиуемое строковое значение не было пустой строкой или не состояло исключительно из пробельных символов.
Применяется к CharSequence и наследникам.
@NotEmpty
Аннотация, требующая, чтобы валидируемое свойство было непустым объектом.
Поддерживаемые типы:
CharSequenceи наследники (length())Collectionи наследники (size())Mapи наследники (size())- Массивы (
length)
@NotNull
Аннотация, требующая, чтобы валидируемое значение было отлично от null.
@Negative
Аннотация, требующая, чтобы валидируемое значение было отрицательным числом.
Поддерживаемые типы:
BigDecimalBigIntegerCharSequencebyte,short,int,long,float,doubleи их классы-обёртки
Значение null считается валидным.
@NegativeOrZero
Аннотация, требующая, чтобы валидируемое значение было отрицательным числом, либо нулём.
Поддерживаемые типы:
BigDecimalBigIntegerCharSequencebyte,short,int,long,float,doubleи их классы-обёртки
Значение null считается валидным.
@Null
Аннотация, требующая, чтобы валидируемое значение было null.
@Past
Аннотация, ограничивающая значение свойства прошедшим временем.
Список поддерживаемых типов идентичен таковому у @Future.
@PastOrPresent
Аннотация, ограничивающая значение свойства прошедшим или настоящим временем.
Список поддерживаемых типов идентичен таковому у @Future.
@Pattern(regex=, flags=)
Аннотация, требующая, чтобы валидируемое значение типа CharSequence соответствовало регулярному выражению.
В свойстве regex указывается регулярное выражение, а в flags — массив флагов.
@Positive
Аннотация, требующая, чтобы валидируемое значение было положительным числом.
Поддерживаемые типы:
BigDecimalBigIntegerCharSequencebyte,short,int,long,float,doubleи их классы-обёртки
Значение null считается валидным.
@PositiveOrZero
Аннотация, требующая, чтобы валидируемое значение было положительным числом, либо нулём.
Поддерживаемые типы:
BigDecimalBigIntegerCharSequencebyte,short,int,long,float,doubleи их классы-обёртки
Значение null считается валидным.
@Size(min=, max=)
Аннотация, ограничивающая размеры значения валидируемого свойства.
Поддерживаемые типы:
CharSequenceи наследники (length())Collectionи наследники (size())Mapи наследники (size())- Массивы (
length)
Свойством min задаётся минимальный размер (включительно), свойством max — максимальный (включительно).
В следующих статьях будет продемонстрировано применение ограничений для валидаций объектов и методов.
