В листинге 3.13 показано несколько способов использования ограничений на уровне метода. Сервис CardValidator проверяет кредитную карту в соответствии с конкретным валидационным алгоритмом. Для этого конструктор использует ограничение @NotNull с параметром ValidationAlgorithm. Затем два метода validate возвращают Boolean (валидна кредитная карта или нет?) с ограничением @AssertTrue для возвращаемого типа и ограничениями @NotNull и @Future у параметров методов.
public class CardValidator {
··private ValidationAlgorithm validationAlgorithm;
··public CardValidator(@NotNull ValidationAlgorithm validationAlgorithm) {
····this.validationAlgorithm = validationAlgorithm;
··}
··@AssertTrue
··public Boolean validate(@NotNull CreditCard creditCard) {
····return validationAlgorithm.validate(creditCard.getNumber(),
creditCard.getCtrlNumber());
··}
··@AssertTrue
··public Boolean validate(@NotNull String number, @Future Date expiryDate,
··Integer controlNumber, String type) {
····return validationAlgorithm.validate(number, controlNumber);
··}
}
Часто в бизнес-модели действует механизм наследования. При использовании валидации компонентов приходится накладывать ограничения на классы, суперклассы или интерфейсы вашей бизнес-модели. Наследование ограничений у свойств работает точно так же, как и обычное наследование в Java: оно является кумулятивным. Таким образом, если один компонент наследует от другого, то ограничения наследуемого компонента также заимствуются и будут валидироваться.
В листинге 3.15 показан класс CD, расширяющий Item (листинг 3.14). Оба класса имеют атрибуты и применяемые с ними ограничения. Если валидируется экземпляр CD, то валидируются не только его ограничения, но и ограничения, налагаемые на родительский класс.
Public class Item {
··@NotNull
··protected Long id;
··@NotNull @Size(min = 4, max = 50)
··protected String title;
··protected Float price;
··protected String description;
··@NotNull
··public Float calculateVAT() {
····return price * 0.196f;
··}
··@NotNull
··public Float calculatePrice(@DecimalMin("1.2") Float rate) {
····return price * rate;
··}
}
public class CD extends Item {
··@Pattern(regexp = "[A-Z][a-z]{1,}")
··private String musicCompany;
··@Max(value = 5)
··private Integer numberOfCDs;
··private Float totalDuration;
··@MusicGenre
··private String genre;
··// ConstraintDeclarationException: не допускается при переопределении метода
··public Float calculatePrice(@DecimalMin("1.4") Float rate) {
····return price * rate;
··}
}
Такой же механизм наследования применяется и с ограничениями, действующими на уровне методов. Метод calculateVAT, объявляемый в Item, наследуется в CD. Но в случае переопределения метода нужно уделять особое внимание при определении ограничений для параметров. Лишь корневой метод переопределяемого метода может аннотироваться ограничениями параметров. Причина такого условия состоит в том, что предусловия нельзя ужесточать для подтипов. Напротив, в подтипах можно добавлять ограничения для возвращаемых значений в любом количестве (постусловия можно ужесточать).
Итак, если вы валидируете calculatePrice класса CD (см. листинг 3.15), среда исполнения валидации компонентов будет выдавать исключение javax.validation.ConstraintDeclarationException. Оно означает, что только корневой метод переопределенного метода может использовать ограничения параметров.
Сообщения