Статьи

Проверяйте графы объектов с помощью аннотации @Valid Java Bean Validation

Аннотация @Valid ограничения Java Bean Validation гарантирует, что при проверке объекта проверка повторяется во всех полях, аннотированных @Valid . Это действительно облегчает выполнение обычно сложной задачи проверки целых графов объектов.

Чтобы разобраться в этом посте, вы должны знать основы использования Java Bean Validation .

Проверка графов объектов за один шаг с @Valid

Чтобы лучше понять, почему аннотация @Valid является такой ценной функцией, я начну с того, что @Valid вам, что нужно сделать для проверки графа объектов, который его не использует.

Раздутый код без @Valid

Рассмотрим случай ограниченного класса A который объявляет зависимость от другого набора ограниченных классов B и C Здесь у нас есть простой граф объектов, где у каждого сотрудника в этой ассоциации есть свой набор ограничений проверки. Без аннотации @Valid проверка графа является довольно трудоемкой задачей, поскольку каждый экземпляр A , B и C необходимо проверять отдельно, с помощью многочисленных вызовов метода validate() реализации интерфейса Validator .

Рассмотрим следующие классы:

 public class AccountProcessor { @NotEmpty(message = "Account number may not be empty") @Size(min = 8, max = 8, message = "Account number must be an 8-digit string") private String accountNumber; public AccountProcessor(String accountNumber) { this.accountNumber = accountNumber; } public void processAccount() { // process the account here } } public class PaymentService { private AccountProcessor accountProcessor; @NotEmpty(message = "Payment method may not be empty") private String paymentMethod; public PaymentService(AccountProcessor accountProcessor, String paymentMethod) { this.accountProcessor = accountProcessor; this.paymentMethod = paymentMethod; } } 

На данный момент нам удалось создать базовый граф объектов с помощью AccountProcessor с использованием AccountProcessor . Без аннотации @Valid график должен проверяться для каждого объекта следующим образом:

 Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); AccountProcessor accountProcessor = new AccountProcessor(""); PaymentService paymentService = new PaymentService(accountProcessor, ""); validator .validate(accountProcessor) .stream() .forEach(violation -> System.out.println(violation.getMessage())); validator .validate(paymentService) .stream() .forEach(violation -> System.out.println(violation.getMessage())); 

В этом случае ни экземпляр AccountProcessor ни его PaymentService не были правильно инициализированы и взяты вместе, что вызовет три нарушения ограничения.

Хотя валидация работает, как и ожидалось, код раздут от необходимости вызывать validate отдельно для каждого экземпляра.

Использование @Valid для @Valid объектов

Чтобы улучшить код проверки, давайте PaymentService рефакторинг класса PaymentService и @Valid аннотацию @Valid с ее полем AccountProcessor :

 public class PaymentService { @Valid private AccountProcessor accountProcessor; // other class members and methods as before } 

Влияние использования аннотации @Valid можно заметить здесь:

 Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); AccountProcessor defaultAccountProcessor = new DefaultAccountProcessor(""); PaymentService paymentService = new PaymentService(defaultAccountProcessor, ""); validator .validate(paymentService) .stream() .forEach(violation -> System.out.println(violation.getMessage())); 

Код более компактен и оптимизирован, но приведет к тому же результату проверки, что и более длинный блок ранее. Всякий раз, когда экземпляр PaymentService проверяется, AccountProcessor будет проверяться рекурсивно. Мы убиваем двух зайцев одним выстрелом!

С точки зрения клиентского кода, проверка, по-видимому, выполняется посредством одного вызова validate() , который является правильным способом сделать это, так как это аккуратно скрывает от разработчика сложности, связанные с сканированием всей структуры графов объектов. Внутренне, однако, метод фактически вызывается рекурсивно, в то время как валидатор пересекает дерево от корневого объекта до конечных объектов. Более того, использование @Valid не ограничивается только полями классов, так как его можно использовать и в коллекциях и массивах.

Это проверка графов объектов стала проще.

Проверяйте весь граф объектов (кто-то сказал дерево?) С аннотацией @Valid

Резюме

Аннотация @Valid является ключевой особенностью Bean Validation, поскольку она позволяет проверять графы объектов с помощью одного вызова валидатора. Чтобы использовать его, все поля, которые должны быть рекурсивно проверены, должны быть аннотированы @Valid .

Еще одна интересная функция, которая выходит за рамки базовой проверки bean-компонентов — это проверка отдельных полей и значений с помощью validateProperty() и validateValue() . API, конечно, может предложить гораздо больше, поэтому обязательно ознакомьтесь с официальными документами и будьте в курсе последних новостей .