Выбрать главу
Листинг 3.1. Объект Book. Ограничения записаны в виде аннотаций

public class Book {

··@NotNull

··private String title;

··@NotNull @Min(2)

··private Float price;

··@Size(max = 2000)

··private String description;

··private String isbn;

··private Integer nbOfPage;

··// Конструкторы, геттеры, сеттеры

}

В листинге 3.1 показан класс Book с атрибутами, конструкторами, геттерами, сеттерами и аннотациями. Некоторые из этих атрибутов аннотированы с применением встроенных ограничений, таких как @NotNull, @Min и @Size. Так мы указываем валидационной среде исполнения, что заголовок title книги не может быть равен нулю и описание description не может превышать 2000 символов. Как видите, к атрибуту могут быть применены несколько ограничений (например, price не может быть равно нулю и его значение не может быть меньше 2).

Внутренняя организация ограничения

Ограничение определяется как комбинация ограничивающей аннотации и списка реализаций валидации ограничения. Ограничивающая аннотация применяется с типами, методами, полями или другими ограничивающими аннотациями (в случае с составными элементами). В большинстве спецификаций Java EE разработчики используют заранее определенные аннотации (например, @Entity, @Stateless и @Path). Но в случае с CDI (об этом шла речь в предыдущей главе) и при валидации компонентов программистам приходится писать собственные аннотации. Известно, что ограничение при валидации компонентов состоит из:

• аннотации, определяющей ограничение;

• списка классов, реализующих ограничивающий алгоритм с заданным типом.

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

Ограничивающая аннотация

Ограничение, применяемое с JavaBean, выражается с помощью одной или нескольких аннотаций. Аннотация считается ограничивающей, если применяемая в ней политика хранения содержит RUNTIME и если сама она аннотирована javax.validation.Constraint (эта аннотация ссылается на список реализаций валидации). В листинге 3.2 показана ограничивающая аннотация NotNull. Как видите, @Constraint(validatedBy = {}) указывает на класс реализации NotNullValidator.

Листинг 3.2. Ограничивающая аннотация NotNull

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})

@Retention(RUNTIME)

@Documented

@Constraint(validatedBy = NotNullValidator.class)

public @interface NotNull {

··String message() default "{javax.validation.constraints.NotNull.message}";

··Class<?>[] groups() default {};

··Class<? extends Payload>[] payload() default {};

}

Ограничивающие аннотации — это самые обычные аннотации, поэтому с ними приходится определять своеобразные метааннотации:

• @Target({METHOD, FIELD…}) — указывает цель, для которой может использоваться аннотация (подробнее об этом — ниже);

• @Retention(RUNTIME) — определяет, как мы будем обращаться с аннотацией. Необходимо использовать как минимум RUNTIME, чтобы поставщик мог проверять ваш объект во время выполнения;

• @Constraint(validatedBy = NotNullValidator.class) — указывает класс (в случае агрегации ограничений — нуль либо список классов), в котором инкапсулирован валидационный алгоритм;

• @Documented — определяет, будет эта аннотация включена в Javadoc или нет. Опциональная метааннотация.

Поверх этих общих метааннотаций спецификация Bean Validation требует задавать для каждой ограничивающей аннотации три дополнительных атрибута:

• message — обеспечивает для аннотации возможность возвращения интернационализированного сообщения об ошибке, выдаваемого в том случае, если ограничение недопустимо. По умолчанию данный атрибут равен ключу;

• groups — используется для контроля за порядком, в котором интерпретируются ограничения, либо для выполнения частичной валидации;

• payload — применяется для ассоциирования метаинформации с ограничением.

Если ваше ограничение определяет все обязательные метааннотации и ограничения, можете добавить любой интересующий вас конкретный параметр. Например, ограничение, проверяющее длину строки, может использовать атрибут length для указания максимальной длины.