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

    Не так давно в Яве не существовало стандарта, описывающего способ валидации данных. Каждый выкручивался как мог, писались (и пишутся) свои поделки а так же используются некоторые возможности широко распространенных сервисов как 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, приятных экспериментов!
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 21

      +1
      Спасибо, буду смотреть
        +1
        Спасибо! Отличная статья!=)
          +3
          Объясните пожалуйста, почему в России так часто искажают название данного языка (Java), в то время как носители языка, к которым принадлежат и люди, стоявшие у истоков данной технологии произносят это как «Джава»?
            0
            Вам режет слух?
            Мне его режет, когда произносят немецкие названия: к примеру Рейн вместо Райн, ГанновЕр вместо ХаннОфер, Гейдельберг вместо Хайдельберг. Так же режет слух, когда немцы говорят Москау вместо Москва. Тут такое дело… изменять его нет смысла. Или вы говорите про остров Ява тоже Джава?
            На самом деле дискуссия тут бесполезна и все упирается во вкус и привычку. Я привык произносить по немецки и по рускки Ява по отношению к языку программирования и острову.
              0
              Это конечно режет слух, но дело не в этом. Зачем делать так, чтоб иностранные коллеги вас не понимали? Зачем придумать что-то новое, когда есть устоявшийся во всем мире термин? Ладно бы Вы его придумали, но ведь люди придумавшие термин однозначно называют это по другому? Вам сложно произнести это правильно, хотя бы ради уважения к создателям? Ну давайте дотнет величать каким-нибудь тэнетом — мы же русские у нас все по другому и мы будем карявить термины…
                +1
                люди в теме понимают с пол-пинка:)
                мне кажется вы немного преувиличивате проблему, которой на самом деле нет. С иностранными коллегами идет конверсация на всем понятном языке, к примеру на английском, все термины соответственно применяются относительно к используемому языку.
                  +1
                  В статьях и более менее официальных документах, переводить в русские буквы такие слова, как MySQL, Java и т.п. является плохим тоном. В камментах же это роли не играет. А на счёт произношения Java, мне больше нравится оригинальный вариант [джава], он более сочный, яркий и соответствует тому, как большинство программистов мира его произносит — SAMPA: /''dZA:va/.
                    0
                    плохим тоном (вернее доказательством незрелости) является доказывание с пеной у рта своих взглядов на определенные вещи, принятие этих взглядов как единственно правильные, а так же отторжение альтернатив.

                    Как пример старый баян, кто изображен на картинке, старая или молодая женщина?


                    Слово и название (имя собственное?) Ява не противит правилам русского языка и имеет право на существование. См. мой комментарий выше. Иначе все названия городов в русском языке (да и в других) надо поменять.

                    На этом дискуссию и флэйм предлагаю закрыть/перенести в другой топик и там насладиться развитием этой темы. Пожалуйста далее комментарии только по теме.
              +1
              Несущественно.
                0
                Как раз-таки Джава режет слух, а Ява — ахуительное слово!
                  0
                  Как мотоцикл, сел и поехал… ;-)
                +1
                Это все конечно хорошо, но в реальных предметных областях бывает очень и очень запутанная валидация. Например, одно поле зависит от другого поля или даже объекта, или несколько полей составляют одну ошибку, исправить которую можно изменив значение одного из полей.
                  0
                  ну так тут только знакомство со стандартом. На самом деле ограничения тоже можно довольно «легко» проверять и длля графов из объектов: для этого нужно использовать аннотацию @Valid:
                  import javax.validation.Valid;

                  public class Customer {
                    ...
                    @Valid
                    Address adress;
                    ...
                  }


                  * This source code was highlighted with Source Code Highlighter.

                  при вызове validator.validate(myCustomer); автоматически будет валидироваться и объект класса Address.

                  Так же существиет возможность объединения ограничений по группам и назначения им собственных валидаторов, которые, в свою очередь могут при проверке учитывать и зависимости между полями.
                    0
                    Это уже интереснее, безусловно… Надо будет покурить релиз. Это же в седьмую Джаву войдет, насколько я знаю?
                      0
                      однозначного ответа дать не могу, т.к. насчет седьмого релиза я, к сожалению, не знаю… Даже цель-дату релиза jsr 303 я пока нигде не заметил, но думаю, еще в этом году, так как ревью практически закончено
                  +1
                  А как же i18n? Или для каждого языка свой bean создавать?
                    0
                    Вопроса не совсем понял, но попробую угадать
                    Речь идет о интернализации сообщений?
                    На самом деле все очень просто. Создается ResourceBundle, в нем прописываются properties, к примеру
                    //ValidationMessages.properties
                    User.firstname.notnull=Имя должно быть задано

                    В аннотации прописывается message="{User.firstname.notnull}" и если ValidationMessages.properties находится в корне classpath'а, то {User.firstname.notnull} заменяется на Имя должно быть задано. Разумеется для каждой локали могут быть дефинированы свои ValidationMessages, они будут загружаться автоматически.

                    Разумеется, ResourceBundle может называться как угодно и находиться где угодно, только в этом случае необходимо конфигурировать фэктори. Но это уже другая история:)

                    P.S. лично мое мнение таково, что слово Bean в названии стандарта несколько неправильно, так как валидация может применятся в любом POJO.
                    0
                    Для запуска кода нужен весь жирненький Hibernate или достаточно небольшого jar-ника? Спрашиваю потому, что у меня в проекте используется другая ORM, но данную возможность валидации хотелось бы иметь.
                      0
                      Сам Hibernate совсем не нужен. Валидация работает везде и независит от других библиотек или сервисов.
                      Требуется только validation-api-1.0.CR3.jar, hibernate-validator-4.0.0.Beta2.jar + библиотеки для логгера. Все вместе весит примерно 200-300 Кб и находится в lib дистрибуции по ссылке: https://www.hibernate.org/30.html, далее Hibernate Validator 4.0.0.
                        0
                        Можно ли использовать новый способ валидации в проектах, которые написаны с сипользованием Maven и как это сделать?
                          0
                          я думаю что это возможно, хотя мы сами maven к сожалению не используем, т.к. разрабатываем на OSGi/Equinox.
                          посмотрите в этих репозиториях:
                          <repositories>
                              <repository>
                               <id>jboss</id>
                               <url>repository.jboss.com/maven2</url>
                               <releases>
                                <enabled>true</enabled>
                               </releases>
                               <snapshots>
                                <enabled>false</enabled>
                               </snapshots>
                              </repository>
                               <repository>
                                <id>jboss-snapshot</id>
                                <url>snapshots.jboss.org/maven2</url>
                                <releases>
                                 <enabled>true</enabled>
                                </releases>
                                <snapshots>
                                 <enabled>true</enabled>
                                </snapshots>
                               </repository>
                          </repositories>


                          * This source code was highlighted with Source Code Highlighter.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое