Валидация Interactor

ValidationProxyHandler проверяет аннотации на аргументах перед вызовом обработчика и аннотации на методе после получения результата. При нарушении ограничения выбрасывается BGMessageException.

@BindTextParam(120)
@NotNull(message = "В процессе #objectId не указан номер")
fun getNumber(): String

@BindTextParam(120)
fun setNumber(@NotEmpty(message = "Номер не должен быть пустым") value: String)

В пользовательском message последовательность #objectId заменяется идентификатором, переданным в Interactor.create. Если сообщение не задано и осталось стандартным сообщением javax.validation, формируется техническое сообщение с именем метода или аргумента.

Это собственная точечная реализация ограничений, а не полный запуск Bean Validation. Проверяются только перечисленные ниже аннотации и типы.

Стандартные ограничения

Аннотация Поддерживаемые значения Проверка

@NotNull

Любой тип

Значение не равно null

@Null

Любой тип

Значение равно null

@NotEmpty

String, Collection, Map

Значение не пустое. null пропускается, поэтому для запрета null добавьте @NotNull

@Size

String, Collection, Number

Длина, размер коллекции либо Number.toInt() входит в диапазон min..max. null пропускается

@Pattern

String

Вся строка соответствует regexp. null и другие типы пропускаются

@Email

String

Строка соответствует regexp и flags. Если они не заданы, используются глобальные email.regexp и email.flags

@Positive, @PositiveOrZero, @Negative, @NegativeOrZero

BigDecimal, Double, Float, Long, Int, Short, Byte

Сравнение с нулём; null и другие типы пропускаются

@AssertTrue, @AssertFalse

Boolean

Значение равно ожидаемому; null и другие типы пропускаются

@Future, @FutureOrPresent, @Past, @PastOrPresent

Date, LocalDate, LocalDateTime

Сравнение с текущим временем; LocalDate сравнивается с текущей датой

Стандартные аннотации импортируются из javax.validation.constraints.

Даты с заданной точностью

Пакет ru.bgcrm.util.interactor.annotation содержит собственные Future, FutureOrPresent, Past и PastOrPresent. У них обязательный message и параметр accuracy, по умолчанию ChronoUnit.MILLIS.

@BindDateTimeParam(451)
@ru.bgcrm.util.interactor.annotation.FutureOrPresent(
    message = "Дата не может быть в прошлом",
    accuracy = ChronoUnit.MINUTES
)
fun getPlannedAt(): LocalDateTime?

Поддерживаются MILLIS, SECONDS, MINUTES, HOURS, HALF_DAYS и DAYS. Полученная и текущая даты усекаются до выбранной единицы перед сравнением. Для неподдерживаемой единицы проверка не выполняется.

Особенности одиночных результатов

Несколько обработчиков связей и TMC сначала получают коллекцию, вызывают SizeValidator.assert, а затем возвращают первый элемент. Поэтому @Size(max = 1) на методе с одиночным результатом проверяет размер исходной коллекции, а не объект результата. Это используется в готовых аспектах WithSingleCustomer и WithSingleCctvContract.

@BindProcessLinkedCustomers
@Size(max = 1, message = "К процессу привязано больше одного контрагента")
@NotNull(message = "К процессу не привязан контрагент")
fun getCustomer(): Customer

Порядок общий: входные ограничения → обработчик → выходные ограничения. Если проверка аргумента не пройдена, чтение или изменение данных не начинается.