Где ставятся аннотации валидации, например @NotNull, на уровне класса или полей в Spring
Что проверяют
Знаете ли вы, как устроена Bean Validation в Spring и где на самом деле живут ограничения. Следом обычно спрашивают, как проверить связь двух полей, например совпадение паролей, и почему аннотации «не срабатывают».
Как отвечать
Валидация в Spring Boot это Jakarta Bean Validation с реализацией Hibernate Validator, подключается стартером spring-boot-starter-validation. В Spring Boot 3 импорты идут из jakarta.validation.constraints, а не из javax.
Места для аннотаций:
- поля: основной вариант для DTO,
@NotNull,@NotBlank,@Size,@Emailнад полем; - геттеры: тоже уровень свойства, валидатор вызывает метод. На одном свойстве поле и геттер не смешивают, иначе проверка сработает дважды;
- элементы коллекций:
List<@NotBlank String> tags; - параметры и результаты методов: класс сервиса помечают
@Validated, и Spring проверяет аргументы через прокси; - класс: сюда вешают не
@NotNull, а собственную аннотацию с@Target(TYPE)иConstraintValidator, который получает весь объект. Так проверяют правила на несколько полей: пароль совпадает с подтверждением,dateFromраньшеdateTo.
Сами аннотации ничего не делают, проверку нужно запустить. В контроллере это @Valid @RequestBody UserDto dto: при ошибке Spring бросает MethodArgumentNotValidException и по умолчанию отвечает 400. Для вложенного объекта нужен @Valid на поле, иначе его ограничения пропускаются.
Где спотыкаются
Вешают @Validated на сам DTO и считают это проверкой уровня класса. @Validated нужен бинам Spring для валидации методов и групп, на DTO он ничего не включает.
Путают @NotNull с @NotBlank: пустая строка и строка из пробелов проходят @NotNull без ошибок.
Забывают @Valid в контроллере или стартер в зависимостях. Приложение собирается, аннотации стоят, а невалидные данные спокойно доходят до базы.