Pull to refresh

Знакомство с Bean Validation API

Reading time 4 min
Views 70K
Не так давно в Яве не существовало стандарта, описывающего способ валидации данных. Каждый выкручивался как мог, писались (и пишутся) свои поделки а так же используются некоторые возможности широко распространенных сервисов как Spring или Hibernate. Наибольшей проблемой было то, что валидация могла быть реализована отдельно от предметной модели и быть редунданто расбросанной по фронт- и бэкэнду. Теперь, при помощи стандарта JSR 303: Bean Validation (практически это явлается стандартизированным валидатором Hibernate) становится возможным следовать принципу «Don't Repeat Yourself»: объявлять ограничения для данных прямо в предметной модели и валидировать данные где угодно, хоть на сервере, хоть в десктопном приложении.



Пример использования


package test.validator;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

public class User {

  @NotNull(message="Имя должно быть задано")
  String firstname;

  @NotNull(message="Фамилия должна быть задана")
  @Size(min = 3, message="Длина фамилии должна быть больше трех")
  String lastname;

  @NotNull(message="Имэйл должен быть задан")
  @Pattern(regexp = "^(?:[a-zA-Z0-9_'^&/+-])+(?:\\.(?:[a-zA-Z0-9_'^&/+-])+)" +
      "*@(?:(?:\\[?(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\\.)" +
      "{3}(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\]?)|(?:[a-zA-Z0-9-]+\\.)" +
      "+(?:[a-zA-Z]){2,}\\.?)$",
      message = "заданный имэйл не может существовать")
  String email;

  @Override
  public String toString() {
    return String.format("firstname: [%s], lastname: [%s], email: [%s]",
        firstname, lastname, email);
  }

  public static void validate(Object object, Validator validator) {
    Set<ConstraintViolation<Object>> constraintViolations = validator
        .validate(object);
    
    System.out.println(object);
    System.out.println(String.format("Кол-во ошибок: %d",
        constraintViolations.size()));
    
    for (ConstraintViolation<Object> cv : constraintViolations)
      System.out.println(String.format(
          "Внимание, ошибка! property: [%s], value: [%s], message: [%s]",
          cv.getPropertyPath(), cv.getInvalidValue(), cv.getMessage()));
  }

  public static void main(String[] args) {
    ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
    Validator validator = vf.getValidator();

    User user = new User();
    validate(user, validator);

    user.firstname = "Вася";
    validate(user, validator);

    user.lastname = "Пу";
    validate(user, validator);
    
    user.lastname = "Пупкин";
    validate(user, validator);
    
    user.email = "вася пупкин@example.com";
    validate(user, validator);

    user.email = "vasya.poupkine@example.com";
    validate(user, validator);

  }

}

* This source code was highlighted with Source Code Highlighter.


Таким образом валидация данных проводится в три базовых шага:
  • Объявление «ограничений» (constraints) на данные в модели при помощи аннотаций
  • Получение валидатора через фэктори
  • валидация объектов и обработка сообщений о нарушениях объявленных рамок (ConstraintViolations)

На данный момент существует лишь малое количество аннотаций в еще пока не выпущенном стандарте. Но есть не малая вероятность что такие аннотации как Email, @CreditCard, Password итд. будут доступны хотя бы через провайдеров имплементации стандарта.

На этом закончим знакомство с JSR 303. А с такими подробностями как расширение/написание собственных ограничений, интернализации сообщений, конфигурации фэктори и прочим можно ознакомится и в самом стандарте

P.S. Для запуска кода в примере использовалась имплементация Hibernate 4.0.0 Beta2, приятных экспериментов!
Tags:
Hubs:
+32
Comments 21
Comments Comments 21

Articles