4.2.13.1. Задание ограничений
Ограничения bean validation задаются с помощью аннотаций пакета javax.validation.constraints
или собственных аннотаций. Аннотации указываются на декларации класса сущности или POJO, на поле или getter-методе, а также на методе сервиса middleware.
Пример использования стандартных аннотаций валидации на полях сущности:
@Table(name = "DEMO_CUSTOMER")
@Entity(name = "demo$Customer")
public class Customer extends StandardEntity {
@Size(min = 3) // length of value must be longer then 3 characters
@Column(name = "NAME", nullable = false)
protected String name;
@Min(1) // minimum value
@Max(5) // maximum value
@Column(name = "GRADE", nullable = false)
protected Integer grade;
@Pattern(regexp = "\\S+@\\S+") // value must conform to the pattern
@Column(name = "EMAIL")
protected String email;
//...
}
Пример использования собственной аннотации уровня класса (см. ниже):
@CheckTaskFeasibility(groups = {Default.class, UiCrossFieldChecks.class}) // custom validation annotation
@Table(name = "DEMO_TASK")
@Entity(name = "demo$Task")
public class Task extends StandardEntity {
//...
}
Пример валидации параметров и возвращаемого значения метода сервиса:
public interface TaskService {
String NAME = "demo_TaskService";
@Validated // indicates that the method should be validated
@NotNull
String completeTask(@Size(min = 5) String comment, @NotNull Task task);
}
- Группы ограничений
-
Группы ограничений позволяют применять подмножество всех заданных ограничений в зависисмости от логики приложения. Например, вы можете заставить пользователя ввести значение некоторого атрибута сущности в UI, и а то же время иметь возможность установить данный атрибут в null в некотором внутреннем механизме. Для этого необходимо указать атрибут
groups
в аннотации ограничения, и оно будет действовать только когда эта же группа передается в механизм валидации.Платформа передает в механизм валидации следующие группы ограничений:
-
RestApiChecks
- при валидации в REST API. -
ServiceParametersChecks
- при валидации параметров сервисов. -
ServiceResultChecks
- при валидации возвращаемых значений сервисов. -
UiComponentChecks
- при валидации отдельных полей в UI. -
UiCrossFieldChecks
- при валидации ограничений уровня класса на коммите экрана редактора сущности. -
javax.validation.groups.Default
- данная группа передается во всех случаях кроме коммита экрана редактора сущности.
-
- Сообщения валидации
-
Ограничения могут иметь сообщения для отображения пользователям.
Сообщения могут быть указаны непосредственно в аннотациях валидации, например:
@Pattern(regexp = "\\S+@\\S+", message = "Invalid format") @Column(name = "EMAIL") protected String email;
Сообщения можно также поместить в пакет локализованных сообщений и использовать следующий формат указания сообщения в аннотации:
{msg://message_pack/message_key}
. Например:@Pattern(regexp = "\\S+@\\S+", message = "{msg://com.company.demo.entity/Customer.email.validationMsg}") @Column(name = "EMAIL") protected String email;
Сообщения могут содержать параметры и выражения. Параметры заключаются в фигурные скобки
{}
и представляют собой либо указатели на локализованные сообщения (см. выше) или параметры аннотации, например{min}
,{max}
,{value}
. Выражения заключаются в фигурные скобки со знаком доллара${}
и могут включать валидируемое значение в виде переменнойvalidatedValue
, параметры аннотации типаvalue
илиmin
, и выражения JSR-341 (EL 3.0). Например:@Pattern(regexp = "\\S+@\\S+", message = "Invalid email: ${validatedValue}, pattern: {regexp}") @Column(name = "EMAIL") protected String email;
Значения локализованных сообщений также могут содержать параметры и выражения.
- Собственные ограничения
-
В проекте можно создать собственные ограничения с программной или декларативной валидацией.
Для создания ограничения с программной валидацией выполниет следующее:
-
Создайте аннотацию в модуле global проекта и добавьте ей аннотацию
@Constraint
. Ваша аннотация должна содержать атрибутыmessage
,groups
иpayload
:@Target({ ElementType.TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = TaskFeasibilityValidator.class) public @interface CheckTaskFeasibility { String message() default "{msg://com.company.demo.entity/CheckTaskFeasibility.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
-
Создайте класс валидатора в модуле global проекта:
public class TaskFeasibilityValidator implements ConstraintValidator<CheckTaskFeasibility, Task> { @Override public void initialize(CheckTaskFeasibility constraintAnnotation) { } @Override public boolean isValid(Task value, ConstraintValidatorContext context) { Date now = AppBeans.get(TimeSource.class).currentTimestamp(); return !(value.getDueDate().before(DateUtils.addDays(now, 3)) && value.getProgress() < 90); } }
-
Используйте аннотацию:
@CheckTaskFeasibility(groups = UiCrossFieldChecks.class) @Table(name = "DEMO_TASK") @Entity(name = "demo$Task") public class Task extends StandardEntity { @Future @Temporal(TemporalType.DATE) @Column(name = "DUE_DATE") protected Date dueDate; @Min(0) @Max(100) @Column(name = "PROGRESS", nullable = false) protected Integer progress; //... }
Собственные аннотации могут также быть созданы как композиции имеющихся, например:
@NotNull @Size(min = 2, max = 14) @Pattern(regexp = "\\d+") @Target({METHOD, FIELD, ANNOTATION_TYPE}) @Retention(RUNTIME) @Constraint(validatedBy = {}) public @interface ValidProductCode { String message() default "{msg://om.company.demo.entity/ValidProductCode.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
При использовании композитных ограничений результирующий набор нарушений
ConstraintViolation
будет содержать отдельные записи для каждого включенного ограничения. Для того, чтобы получить одну запись нарушения, добавьте@ReportAsSingleViolation
классу вашей аннотации. -