Рубрики
Без рубрики

Введение в API проверки Vavr

Узнайте об API проверки Vavr и о том, как использовать его наиболее релевантные методы.

Автор оригинала: baeldung.

1. Обзор

Валидация-это часто встречающаяся задача в приложениях Java, и поэтому в разработку библиотек валидации было вложено много усилий.

Vavr (ранее известный как Javaslang) предоставляет полноценный API проверки|/. Это позволяет нам проверять данные простым способом, используя объектно-функциональный стиль программирования. Если вы хотите взглянуть на то, что эта библиотека предлагает из коробки, не стесняйтесь проверить эту статью .

В этом уроке мы подробно рассмотрим API проверки библиотеки и узнаем, как использовать ее наиболее релевантные методы.

2. Интерфейс Проверки

Интерфейс проверки Vavr основан на концепции функционального программирования, известной как прикладной функтор . Он выполняет последовательность функций, накапливая результаты, даже если некоторые или все эти функции выходят из строя во время цепочки выполнения.

Прикладной функтор библиотеки построен на исполнителях ее интерфейса Validation . Этот интерфейс предоставляет методы для накопления ошибок проверки и проверенных данных, что позволяет обрабатывать их как пакет.

3. Проверка Ввода Пользователем

Проверка вводимых пользователем данных (например, данных, собранных с веб-уровня) проходит гладко с помощью API проверки, поскольку она сводится к созданию пользовательского класса проверки, который проверяет данные, накапливая результирующие ошибки, если таковые имеются.

Давайте проверим имя пользователя и адрес электронной почты, которые были отправлены через форму входа в систему. Во-первых, нам нужно включить артефакт Var Maven в pom.xml файл:


    io.vavr
    vavr
    0.9.0

Далее, давайте создадим класс домена, который моделирует пользовательские объекты:

public class User {
    private String name;
    private String email;
    
    // standard constructors, setters and getters, toString
}

Наконец, давайте определим наш пользовательский валидатор:

public class UserValidator {
    private static final String NAME_PATTERN = ...
    private static final String NAME_ERROR = ...
    private static final String EMAIL_PATTERN = ...
    private static final String EMAIL_ERROR = ...
	
    public Validation, User> validateUser(
      String name, String email) {
        return Validation
          .combine(
            validateField(name, NAME_PATTERN, NAME_ERROR),
            validateField(email, EMAIL_PATTERN, EMAIL_ERROR))
          .ap(User::new);
    }
	
    private Validation validateField
      (String field, String pattern, String error) {
 
        return CharSeq.of(field)
          .replaceAll(pattern, "")
          .transform(seq -> seq.isEmpty() 
            ? Validation.valid(field) 
            : Validation.invalid(error));		
    }
}

Класс UserValidator проверяет указанное имя и адрес электронной почты индивидуально с помощью метода validateField () . В этом случае этот метод выполняет типичное сопоставление шаблонов на основе регулярных выражений.

Суть в этом примере заключается в использовании методов valid() , invalid() и combine () .

4. Методы valid(), invalid() и combine()

Если указанное имя и адрес электронной почты соответствуют заданным регулярным выражениям, метод validateField() вызывает valid() . Этот метод возвращает экземпляр Validation.Действителен . И наоборот, если значения недопустимы, метод invalid() возвращает экземпляр Validation.Недействительно .

Этот простой механизм, основанный на создании различных экземпляров Validation в зависимости от результатов проверки, должен дать нам, по крайней мере, базовое представление о том, как обрабатывать результаты (подробнее об этом в разделе 5).

Наиболее важным аспектом процесса проверки является метод combine () . Внутренне этот метод использует проверку .Класс Builder , который позволяет объединить до 8 различных экземпляров Validation , которые могут быть вычислены различными методами:

static  Builder combine(
  Validation validation1, Validation validation2) {
    Objects.requireNonNull(validation1, "validation1 is null");
    Objects.requireNonNull(validation2, "validation2 is null");
    return new Builder<>(validation1, validation2);
}

Самый простой Валидация.Класс Builder принимает два экземпляра проверки:

final class Builder {

    private Validation v1;
    private Validation v2;

    // standard constructors

    public  Validation, R> ap(Function2 f) {
        return v2.ap(v1.ap(Validation.valid(f.curried())));
    }

    public  Builder3 combine(
      Validation v3) {
        return new Builder3<>(v1, v2, v3);
    }
}

Утверждение.Builder, вместе с методом ap(Функция) , возвращает один единственный результат с результатами проверки. Если все результаты верны, метод ap(Функция) сопоставляет результаты с одним значением. Это значение хранится в экземпляре Valid с помощью функции, указанной в его сигнатуре.

В нашем примере, если указанные имя и адрес электронной почты действительны, создается новый объект User . Конечно, можно сделать что-то совершенно другое с действительным результатом, то есть занести его в базу данных, отправить по электронной почте и так далее.

5. Обработка Результатов Валидации

Довольно легко реализовать различные механизмы обработки результатов проверки. Но как мы в первую очередь проверяем данные? В этой степени мы используем класс UserValidator :

UserValidator userValidator = new UserValidator(); 
Validation, User> validation = userValidator
  .validateUser("John", "[email protected]");

После получения экземпляра Validation мы можем использовать гибкость API проверки и обрабатывать результаты несколькими способами.

Давайте подробнее остановимся на наиболее часто встречающихся подходах.

5.1. Действительные и Недействительные экземпляры

Этот подход на сегодняшний день является самым простым. Он состоит из проверки результатов проверки с помощью экземпляров Valid и Invalid :

@Test
public void 
  givenInvalidUserParams_whenValidated_thenInvalidInstance() {
    assertThat(
      userValidator.validateUser(" ", "no-email"), 
      instanceOf(Invalid.class));
}
	
@Test
public void 
  givenValidUserParams_whenValidated_thenValidInstance() {
    assertThat(
      userValidator.validateUser("John", "[email protected]"), 
      instanceOf(Valid.class));
}

Вместо того, чтобы проверять достоверность результатов с помощью экземпляров Valid и Invalid , мы должны просто сделать еще один шаг вперед и использовать методы isValid() и IsInvalid () .

5.2. Недопустимые() и недействительные() API

Использование тандема допустимо() / недопустимо() аналогично предыдущему подходу, с той разницей , что эти методы возвращают true или false , в зависимости от результатов проверки:

@Test
public void 
  givenInvalidUserParams_whenValidated_thenIsInvalidIsTrue() {
    assertTrue(userValidator
      .validateUser("John", "no-email")
      .isInvalid());
}

@Test
public void 
  givenValidUserParams_whenValidated_thenIsValidMethodIsTrue() {
    assertTrue(userValidator
      .validateUser("John", "[email protected]")
      .isValid());
}

Экземпляр Invalid содержит все ошибки проверки. Их можно извлечь с помощью метода getError() :

@Test
public void 
  givenInValidUserParams_withGetErrorMethod_thenGetErrorMessages() {
    assertEquals(
      "Name contains invalid characters, Email must be a well-formed email address", 
      userValidator.validateUser("John", "no-email")
        .getError()
        .intersperse(", ")
        .fold("", String::concat));
 }

И наоборот, если результаты верны, экземпляр User можно захватить с помощью метода get() :

@Test
public void 
  givenValidUserParams_withGetMethod_thenGetUserInstance() {
    assertThat(userValidator.validateUser("John", "[email protected]")
      .get(), instanceOf(User.class));
 }

Этот подход работает, как и ожидалось, но код по-прежнему выглядит довольно многословным и длинным. Мы можем сжать его дальше, используя метод в любой () .

5.3. API to Either()

Метод to Either() конструирует Left и Right экземпляры интерфейса Either . Этот дополнительный интерфейс имеет несколько удобных методов, которые могут быть использованы для сокращения обработки результатов проверки.

Если результаты действительны, результат сохраняется в экземпляре Right . В нашем примере это будет равносильно допустимому объекту User . И наоборот, если результаты неверны, ошибки сохраняются в экземпляре Left :

@Test
public void 
  givenValidUserParams_withtoEitherMethod_thenRightInstance() {
    assertThat(userValidator.validateUser("John", "[email protected]")
      .toEither(), instanceOf(Right.class));
}

Теперь код выглядит гораздо более лаконичным и обтекаемым. Но мы еще не закончили. Интерфейс Validation предоставляет метод fold () , который применяет пользовательскую функцию, которая применяется к допустимым результатам, а другая-к недопустимым.

5.4. API fold()

Давайте посмотрим, как использовать метод fold() для обработки результатов проверки:

@Test
public void 
  givenValidUserParams_withFoldMethod_thenEqualstoParamsLength() {
    assertEquals(2, (int) userValidator.validateUser(" ", " ")
      .fold(Seq::length, User::hashCode));
}

Использование fold() сокращает обработку результатов проверки до одной строки.

Стоит подчеркнуть, что типы возвращаемых функций, передаваемые в качестве аргументов методу, должны быть одинаковыми. Кроме того, функции должны поддерживаться параметрами типа, определенными в классе проверки, т. е. Seq и User .

6. Заключение

В этой статье мы подробно изучили API проверки Vavr и узнали, как использовать некоторые из его наиболее релевантных методов. Для получения полного списка проверьте official docs API .

Контроль проверки Vavr обеспечивает очень привлекательную альтернативу более традиционным реализациям проверки Java Beans, таким как Hibernate Validator .

Как обычно, все примеры, приведенные в статье, доступны на GitHub .