Содержание
Аннотация @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
является ключевой особенностью Bean Validation, поскольку она позволяет проверять графы объектов с помощью одного вызова валидатора. Чтобы использовать его, все поля, которые должны быть рекурсивно проверены, должны быть аннотированы @Valid
.
Еще одна интересная функция, которая выходит за рамки базовой проверки bean-компонентов — это проверка отдельных полей и значений с помощью validateProperty()
и validateValue()
. API, конечно, может предложить гораздо больше, поэтому обязательно ознакомьтесь с официальными документами и будьте в курсе последних новостей .