В этой статье, посвящённой Jakarta Bean Validation, будет подробно рассмотрен процесс валидации методов, а также применение ограничений к аргументам и возвращаемым значениям методов и конструкторов. Кроме этого будет рассмотрено каскадирование валидации, а так же нюансы валидации методов при использовании наследования.
Цикл статей о Jakarta Bean Validation
Данная статья является частью цикла статей о Jakarta Bean Validation:
- Знакомство с Jakarta Bean Validation 3.0
- Валидация объектов
- Валидация методов (Вы сейчас её читаете)
- Группы валидации (В процессе написания)
- Создание ограничения и валидатора (В процессе написания)
- Интерполяция сообщений (В процессе написания)
- Конфигурация валидатора (В процессе написания)
Валидация методов
Кроме валидации объектов при использовании Jakarta Bean Validation доступна валидация аргументов и возвращаемых значений методов и конструкторов.
Валидация методов возможна при помощи интерфейса ExecutableValidator
, получить экземпляр которого можно при помощи метода forExecutables()
интерфейса Validator
, как это показано в следующем примере кода:
Валидация аргументов методов
Ограничения могут применяться к аргументам методов, в этом случае аннотацией ограничения отмечается валидируемый аргумент:
В XML эти ограничения задаются при помощи <parameter>
следующим образом:
Провести валидацию аргументов метода setAge
можно при помощи метода validateParameters
, который принимает следующие аргументы:
- Валидируемый объект
- Валидируемый метод
- Массив с аргументами метода
- Список групп валидации
В коде это будет выглядеть следующим образом:
Как видно из примера кода, для валидации аргументов метода требуется получить валидируемый метод при помощи API рефлексии.
Валидация аргумента конструктора выглядит схожим образом, но с использованием метода validateConstructorParameters
, который принимает следующие аргументы:
- Валидируемый конструктор
- Массив с аргументами конструктора
- Список групп валидации
Перекрёстные ограничения
При работе с методами могут возникать ситуации, когда в рамках одной проверки требуется проверить значения нескольких аргументов одновременно. В таких ситуациях может быть полезным перекрёстное ограничение, которое применяется сразу к нескольким аргументам метода. Аннотация ограничения в этом случае применяется к самому методу, а не к аргументам:
Jakarta Bean Validation не предоставляет стандартных перекрёстных ограничений, поэтому я использовал своё ограничение для демонстрации:
Про создание и использование собственных ограничений будет рассказано в следующей статье.
В XML перекрёстные ограничения указываются при помощи <cross-parameter>
следующим образом:
Валидация возвращаемого значения метода
В случае с методами и конструкторами ограничения также применимы к возвращаемым значениям. Аннотация ограничения в этом случае также применяется к методу:
В случае с конструктором будет провалидирован созданный им экземпляр класса.
В XML ограничения возвращаемых значений задаются при помощи <return-value>
:
При работе с методами можно проводить и валидацию возвращаемых значений при помощи метода validateReturnValue
, который принимает следующие аргументы:
- Валидируемый объект
- Валидируемый метод
- Валидируемое значение, возвращённое методом
- Список групп валидации
Выглядит валидация возвращаемого значения метода следующим образом:
Конструкторы, как известно, возвращают созданные ими экземпляры классов. Результаты выполнения конструкторов тоже можно проверить. Его валидация будет выглядеть следующим образом:
Каскадирование валидации методов
При необходимости есть возможность использования каскадирования валидации методов, так же как и в случае с валидацией объектов. Если требуется провалидировать аргумент или возвращаемое значение метода или конструктора, то необходимо нужный элемент отметить аннотацией @Valid
:
Того же эффекта можно добиться в XML при помощи <valid/>
:
Ограничения методов при наследовании
При использовании ограничений методов следует помнить о двух правилах:
- Предусловия не могут быть усилены в классах-наследниках
- Постусловия не могут быть ослаблены в классах-наследниках
Эти ограничения восходят к принципу подстановки Барбары Лисков (Liskov Substitution Principle; LSP) из списка принципов SOLID, про который я рассказывал ранее в одной из статей.
Jakarta Bean Validation строго следует этим правилам, и соблюдает первое из них запрещая применение ограничений к аргументам методов дочерних классов, если к аргументам метода родительского класса или интерфейса уже применены ограничения.
Допустим, есть интерфейс ParentCandidatesGroup
, который объявляет метод addCandidate
с ограничениями аргументов. Тогда объявление любых ограничений к этому методу в классе-наследнике будет приводить к ошибке даже в том случае, если ограничения применяются к другим аргументам, так как это в целом является усилением предусловий:
Пример такой ошибки:
1 |
jakarta.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method CandidatesGroup#addCandidate(int, Gender) redefines the configuration of ParentCandidatesGroup#addCandidate(int, Gender). |
Кроме этого, если класс расширяет или реализует два независимых класса или интерфейса, объявляющих метод с одинаковой сигнатурой, то к такому методу ограничения могут быть применены только в реализующем классе, но не в родительских классах:
В противном случае попытка валидации завершится следующей ошибкой:
1 |
jakarta.validation.ConstraintDeclarationException: HV000152: Two methods defined in parallel types must not declare parameter constraints, if they are overridden by the same method, but methods ParentCandidatesGroup#addCandidate(int, Gender) and CandidateArchive#addCandidate(int, Gender) both define parameter constraints. |
В случае с возвращаемыми значениями методов всё работает с точностью до наоборот: ограничения для них могут быть указаны в родительских типах, а так же в дочерних, так как это не является ослаблением постусловий, и при валидации все они будут проверяться.