Валидация методов — Jakarta Bean Validation

В этой статье, посвящённой 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 с ограничениями аргументов. Тогда объявление любых ограничений к этому методу в классе-наследнике будет приводить к ошибке даже в том случае, если ограничения применяются к другим аргументам, так как это в целом является усилением предусловий:

Пример такой ошибки:

Кроме этого, если класс расширяет или реализует два независимых класса или интерфейса, объявляющих метод с одинаковой сигнатурой, то к такому методу ограничения могут быть применены только в реализующем классе, но не в родительских классах:

В противном случае попытка валидации завершится следующей ошибкой:

В случае с возвращаемыми значениями методов всё работает с точностью до наоборот: ограничения для них могут быть указаны в родительских типах, а так же в дочерних, так как это не является ослаблением постусловий, и при валидации все они будут проверяться.

Полезные ссылки