Стисло про Bean Validation

Spring Framework забезпечує підтримку API-інтерфейсу Java Bean Validation Bean Validation забезпечує загальний спосіб перевірки достовірності за допомогою оголошення обмежень і метаданих для Java-додатків. Щоб використовувати його, ти анотуєш властивості моделі предметної області декларативними обмеженнями перевірки достовірності, які потім застосовують середовище виконання. Існують вбудовані обмеження, але ви також можете визначити власні обмеження.

Розглянемо наступний приклад, в якому показана проста модель PersonForm з двома властивостями:

Java

public class PersonForm {
    private String name;
    private int age;
}
Kotlin

class PersonForm(
        private val name: String,
        private val age: Int
)

Bean Validation дозволяє оголошувати обмеження, як показано в наступному прикладі:

Java
public class PersonForm {
    @NotNull
    @Size(max=64)
    private String name;
    @Min(0)
    private int age;
}
Kotlin
class PersonForm(
    @get:NotNull @get:Size(max=64)
    private val name: String,
    @get:Min(0)
    private val age: Int
)

Потім валідатор Bean Validation перевіряє екземпляри цього класу, ґрунтуючись на оголошених обмеженнях. Загальну інформацію про цей API-інтерфейс див. у розділі "Bean Validation". Конкретні обмеження див. у документації Hibernate Validator. Щоб дізнатися, як налаштувати постачальника перевірки достовірності бінів як бін Spring, продовжуй читати. Validation як бін Spring. Це дозволяє впроваджувати javax.validation.ValidatorFactory або javax.validation.Validator усюди, де потрібна перевірка достовірності в додатку.

Ти можеш використовувати LocalValidatorFactoryBean для налаштування валідатора за замовчуванням як бін Spring, як показано в наступному прикладі:

Java
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppConfig {
    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }
}
XML
<bean id="validator"
    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

Базова конфігурація в попередньому прикладі викликає ініціалізацію перевірки достовірності бінів, використовуючи механізм завантаження за замовчуванням. Постачальник Bean Validation, такий як Hibernate Validator, повинен знаходитися в шляху класів і визначатися автоматично.

Впровадження валідатора

LocalValidatorFactoryBean реалізує як ValidatorFactory та javax.validation.Validator, так і org.springframework.validation.Validator зі Spring. Ти можеш впровадити посилання на будь-який з цих інтерфейсів в біни, які повинні викликати логіку перевірки достовірності.

Можна впровадити посилання на javax.validation.Validator, якщо надається перевага прямій роботі з API-інтерфейсом Bean Validation, як показано в наступному прикладі:

Java
import javax.validation.Validator;
@Service
public class MyService {
    @Autowired
    private Validator validator;
}
Kotlin
import javax.validation.Validator;
@Service
class MyService(@Autowired private val validator: Validator)

Можна ввести посилання на org.springframework.validation.Validator, якщо бін вимагає API-інтерфейс Spring Validation, як показано в наступному прикладі:

Java
import org.springframework.validation.Validator;
@Service
public class MyService {
    @Autowired
    private Validator validator;
}
Kotlin
import org.springframework.validation.Validator
@Service
class MyService(@Autowired private val validator: Validator)

Налаштування спеціальних обмежень

Кожне обмеження перевірки достовірності бінів складається з двох частин:

  • Анотації @Constraint, яка оголошує обмеження та його властивості, що налаштовуються.

  • Реалізації інтерфейсу javax.validation.ConstraintValidator, який реалізує логіку роботи обмеження.

Щоб зв'язати оголошення з реалізацією, кожна анотація @Constraint посилається на відповідний клас реалізації ConstraintValidator . Під час виконання ConstraintValidatorFactory створює екземпляр реалізації, на яку посилаються, якщо анотація обмеження зустрічається у твоїй моделі предметної області.

За замовчуванням LocalValidatorFactoryBean конфігурує SpringConstraintValidatorFactory, яка використовує Spring для створення екземплярів ConstraintValidator. Це дозволяє спеціальним ConstraintValidators користуватися впровадженням залежностей, як і будь-яким іншим біном Spring.

У наступному прикладі показано спеціальне оголошення @Constraint, за яким слідує пов'язана реалізація ConstraintValidator, що використовує Spring для впровадження залежностей:

Java

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
Kotlin

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator::class)
annotation class MyConstraint
Java

import javax.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
    @Autowired;
    private Foo aDependency;
    // ...
}
Kotlin

import javax.validation.ConstraintValidator
class MyConstraintValidator(private val aDependency: Foo) : ConstraintValidator {
    // ...
}

Як випливає з попереднього прикладу, реалізація ConstraintValidator може мати свої залежності, позначені анотацією @Autowired, як і будь-який інший бін Spring.

Перевірка достовірності методів, керована Spring

Ти можеш впровадити функцію перевірки методів, що підтримується Bean Validation 1.1 (і, як спеціальне розширення, також Hibernate Validator 4.3), до контексту Spring через визначення біна MethodValidationPostProcessor:

Java
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class AppConfig {
    @Bean
    public MethodValidationPostProcessor validationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}
XML
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/ >

Щоб здійснювати перевірку достовірності методів, керовану Spring, всі цільові класи повинні бути анотовані анотацією @Validated зі Spring, в якій за бажанням можна також оголосити групи перевірки достовірності для використання. Див. MethodValidationPostProcessor для отримання більш детальної інформації про налаштування з використанням постачальників Hibernate Validator та Bean Validation 1.1.

Перевірка достовірності методів використовує АОП-проксі в обхід цільових класів або динамічні проксі з JDK для методів на інтерфейсах або проксі з CGLIB. Існують певні обмеження під час використання проксі. До того ж, пам'ятай, що для проксованих класів завжди потрібно використовувати методи та акцесори; прямий доступ до полів працювати не буде.

Додаткові параметри конфігурації

Конфігурація LocalValidatorFactoryBean за замовчуванням є достатньою для більшості випадків. Існує низка опцій конфігурації для різних конструкцій Bean Validation від інтерполяції повідомлень до дозволу обходу. Див. javadoc LocalValidatorFactoryBean для отримання додаткової інформації про ці опції.

Конфігурування DataBinder

Починаючи зі Spring 3 ти можеш конфігурувати екземпляр DataBinder за допомогою Validator. Після конфігурації можна викликати Validator, якщо звернутися до binder.validate(). Будь-які Errors перевірки достовірності автоматично додаються до прив'язки BindingResult.

У наступному прикладі показано, як програмно використовувати DataBinder для виклику логіки перевірки достовірності після прив'язування до цільового об'єкта:

Java

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());
// прив'язуємо до цільового об'єкта
binder.bind(propertyValues);
// валідуємо цільовий об'єкт
binder.validate();
// отримуємо результат BindingResult, що включає всі помилки валідації
BindingResult results = binder.getBindingResult();
Kotlin

val target = Foo()
val binder = DataBinder(target)
binder.validator = FooValidator()
// прив'язуємо до цільового об'єкта
binder.bind(propertyValues)
// валідуємо цільовий об'єкт
binder.validate()
// отримуємо результат BindingResult, що включає всі помилки валідації
val results = binder.bindingResult

Також можна налаштувати DataBinder з використанням декількох екземплярів Validator через dataBinder.addValidators і dataBinder.replaceValidators. Це доречно у комбінуванні глобально зконфігурованої валідації бінів із використанням Validator зі Spring, налаштованого локально для екземпляра DataBinder.