Для валидации данных в Java EE существует Bean Validation. Первая версия данного набора API была специфицирована в JSR-303 и опубликована как часть Java EE 6. Текущая версия — 2.0, является частью Java EE 8 и описана в JSR-380. Эталонной реализацией Bean Validation является Hibernate Validator. Bean Validation может использоваться не только в классических приложениях на основе Java EE, но и в приложениях на основе Spring, и даже в приложениях, не имеющих отношения к Java EE.
Важно!
Эта статья посвящена устаревшей спецификации Java Bean Validation 2.0! Недавно я записал большой, посвящённый Jakarta Bean Validation и начал писать обновлённый цикл статей:
- Знакомство с Jakarta Bean Validation 3.0
- Валидация объектов — Jakarta Bean Validation
- Валидация методов — Jakarta Bean Validation
Рекомендую ознакомиться с этими статьями. По мере написания новых статей этот список будет обновляться.
Зависимости
Для использования API Bean Validation потребуется зависимость validation-api из javax.validation:
Если вы разрабатываете проект на чистом Java EE, то каких-либо других зависимостей вам не понадобится, более того можно использовать соответствующую версию javaee-api, так как API Bean Validation включены в неё.
В противном случае вам понадобятся ещё две зависимости: реализация Bean Validation и EL (Expression Language, язык выражений). В качестве реализации Bean Validation логичнее всего использовать эталонную реализацию — Hibernate Validator, а в качестве реализации EL можно использовать реализацию от Glassfish:
Теперь можно приступать к изучению ограничений/правил.
Получение валидатора
Самый простой способ получения валидатора — создать фабрику валидаторов по умолчанию и запросить у неё валидатор.
1 2 3 4 5 6 7 8 |
public class ValidationFactoryExample { public static void main(String[] args) { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); Validator validator = validatorFactory.getValidator(); // ... } } |
В дальнейшем полученный объект типа Validator можно использовать для валидации объектов, аргументов, передаваемых в методы и значений, возвращаемых методами.
Ограничения
Правила валидации в Bean Validation задаются при помощи ограничений (constraints), аннотаций, расположенных в пакете javax.validation.constraints. Ограничения могут применяться к свойствам классов, аргументам методов и конструкторов, их возвращаемым значениям, а так же к типам обобщений.
Стандартный набор ограничений включает в себя наиболее часто используемые и универсальные. Кроме того, Bean Validation позволяет разработчикам добавлять собственные ограничения.
Числовые ограничения
@DecimalMax
Применима к переменным типов BigDecimal, BigInteger, CharSequence, byte, short, int, long и их классов-обёрток. Значение должно быть меньше, либо равно указанному значению, либо быть null для непримитивов.
@DecimalMin
Аналогична @DecimalMax, значение переменной должно быть числом и быть больше, либо равной указанной значению, либо быть null для непримитивов.
@Digits
Количество символов слева от запятой должно быть меньше, либо равным integer, а справа — меньше, либо равным fraction, null является валидным значением. Применима к BigDecimal, BigInteger, CharSequence, byte, short, int, long и их классам-обёртам.
@Max
Значение должно быть меньше, либо равно указанному значению, либо быть null. Применима к переменным типов BigDecimal, BigInteger, byte, short, int, long и их классов-обёрток.
@Min
Значение должно быть больше, либо равно указанному значению, либо быть null. Применима к переменным типов BigDecimal, BigInteger, byte, short, int, long и их классов-обёрток.
@Negative
Значение должно быть отрицательным, либо быть null. Применима к переменным типов BigDecimal, BigInteger, byte, short, int, long и их классов-обёрток.
@NegativeOrZero
Значение должно быть отрицательным, равняться 0, либо быть null. Применима к переменным типов BigDecimal, BigInteger, byte, short, int, long и их классов-обёрток.
@Positive
Значение должно быть положительным, либо быть null. Применима к переменным типов BigDecimal, BigInteger, byte, short, int, long и их классов-обёрток.
@PositiveOrZero
Значение должно быть отрицательным, равняться 0, либо быть null. Применима к переменным типов BigDecimal, BigInteger, byte, short, int, long и их классов-обёрток.
Ограничения даты и времени
@Future
Значение переменной должно быть будущим временем. Применима к Date, Calendar и многим типам из пакета java.time.
@FutureOrPresent
Значение переменной должно быть будущим либо настоящим временем. Применима к Date, Calendar и многим типам из пакета java.time.
@Past
Значение переменной должно быть прошедшим временем. Применима к Date, Calendar и многим типам из пакета java.time.
@PastOrPresent
Значение переменной должно быть прошедшим либо настоящим временем. Применима к Date, Calendar и многим типам из пакета java.time.
Строчные ограничения
Значение должно быть адресом электронной почты; применима к CharSequence. Поведение зависит от конкретной реализации.
@NotBlank
Значение типа CharSequence не должно быть null, пустым или состоять из одних лишь пробельных символов.
@Pattern
Значение типа CharSequence должно соответствовать указанному регулярному выражению.
Булевые ограничения
@AssertFalse
Аннотация применима к переменным типов boolean и Boolean, значение которых должно быть false, либо null.
@AssertTrue
Противоположность @AssertFalse, значение должно быть true или null.
Универсальные
@NotEmpty
Значение типов CharSequence, Collection, Map или массив не должно быть null и должно содержать хотя бы 1 элемент.
@NotNull
Значение не должно быть null.
@Null
Значение должно быть null.
@Size
Размер значения типов CharSequence, Collection, Map или массива должен быть в указанном диапазоне — между min и max.
Валидация свойств
Для валидации свойств классов достаточно одну или несколько из вышеперечисленных аннотаций применить к нужному свойству, например:
1 2 3 4 5 6 |
public class Event { @NotNull @PastOrPresent private Date dateCreated; } |
При валидации объекта типа Event будет произведена проверка, что свойство dateCreated содержит дату, значение которой — текущее или прошедшее время.
Пример валидации:
1 2 3 4 5 6 7 8 9 |
public class ValidationFactoryExample { public static void main(String[] args) { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); Validator validator = validatorFactory.getValidator(); Set<ConstraintViolation<Event>> violations = validator.validate(new Event()); } } |
Метод validate валидатора вернёт непустой список нарушений (ConstraintViolation), если свойства объекта нарушают правила валидации.
Валидация аргументов и возвращаемых значений методов
Для валидации аргументов и возвращаемых значений методов (в том числе и конструкторов) можно использовать ExecutableValidator, введённый в Bean Validation 1.1.
Допустим у нас есть класс EventHandler:
1 2 3 4 5 6 7 8 9 10 11 |
public class EventHandler { public EventHandler(@NotNull EventRepository repository) { // .. } @NotNull public Optional<@NotBlank String> handle(@NotNull @Valid Event event) { // .. } } |
Валидация аргументов конструктора и метода handle выполняется следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// constructor args validation Constructor<EventHandler> constructor = EventHandler.class.getConstructor(String.class); Set<ConstraintViolation<EventHandler>> constructorViolations = executableValidator .validateConstructorParameters(constructor, new Object[]{"name"}); EventHandler eventHandler = new EventHandler(repository); Event event = new Event(); // method args validation Method method = eventHandler.getClass() .getMethod("handle", Event.class); Set<ConstraintViolation<EventHandler>> argsViolations = executableValidator .validateParameters(eventHandler, method, new Object[]{event}); // returned value validation String id = eventHandler.handle(event); Set<ConstraintViolation<EventHandler>> returnViolations = executableValidator .validateReturnValue(eventHandler, method, id); |