Bean Validation

Czym jest Bean Validation

Bean Validation jest specyfikacją wchodzącą w skład platformy Java EE i jest oznaczona kodami JSR-303 (wersja 1.0) oraz JSR-349 (wersja 1.1). Aktualnie trwają prace nad wersją 2.0. Najpopularniejszą i jednocześnie referencyjną implementacją jest Hibernate Validator. Alternatywą jest projekt Apache BVal.

bean validation diagram

Bean Validation daje możliwość prostego weryfikowania poprawności pól obiektów w oparciu o zdefiniowane ograniczenia, które stosujemy w postaci adnotacji dodanych nad polami klasami lub metodami dostępowymi (getterami).

public class Person {
    @NotNull
    private String firstName;
    @NotNull
    private String lastName;
    @Email
    private String email;
    @Min(1)
    private int age;
}

Ważną cechą Bean Validation jest integracja z pozostałymi specyfikacjami platformy Java EE takimi jak JPA, czy JAX-RS. BV została również zaadoptowana w Springu, gdzie integruje się także z JPA, Spring Data, czy Spring MVC.

Ograniczenia

Bean Validation definiuje podstawowy zestaw ograniczeń, które powinny nas zadowolić w większości typowych zastosowań:

  • @AssertFalse - musi mieć wartość false
  • @AssertTrue - musi mieć wartość true
  • @Min - określa wartość minimalną
  • @Max - określa wartość maksymalną
  • @DecimalMin - podobnie jak @Min, ale pozwala także na weryfikację liczby w postaci Stringa
  • @DecimalMax -podobnie jak @Max, ale pozwala także na weryfikację liczby w postaci Stringa
  • @Null - musi być null
  • @NotNull - nie może być null@Digits - określa ilość cyfr przed i po przecinku, z ilu może składać się liczba. Wpiera typy całkowitoliczbowe, ich wrappery oraz typy BigInteger i BigDecimal
  • @Future - data musi być z przyszłości
  • @Past - data musi być z przeszłości
  • @Pattern - wartość musi być zgodna z podanym wyrażeniem regularnym
  • @Size - określa minimalną i maksymalną ilość znaków w Stringu lub minimalną i maksymalną ilość elementów w kolekcjach i tablicach

Oprócz wyżej wymienionych istnieje zestaw ograniczeń pochodzących z biblioteki Hibernate Validator:

  • @CreditCardNumber
  • @EAN
  • @Email
  • @Length
  • @LuhnCheck
  • @Mod10Check
  • @Mod11Check
  • @NotBlank
  • @NotEmpty
  • @Range
  • @SafeHtml
  • @ScriptAssert
  • @URL

Przykład

Jeżeli chcesz skorzystać z walidacji w swoim projekcie musisz dodać bibliotekę Hibernate Validator. Najłatwiej jest stworzyć projekt w oparciu o Mavena lub Gradle dodając odpowiednią zależność:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.3.3.Final</version>
</dependency>

W przypadku projektu, gdzie wolimy wszystko robić ręcznie możemy pobrać Hibernate Validatora z oficjalnej strony i wybrać w projekcie opcję Add to Build Path.

build path validation

W projekcie definiujemy klasę reprezentującą osobę, dodając do niej ograniczenia:

  • imię ani nazwisko nie może być wartością null
  • email musi być poprawnym adresem email
  • wiek musi wynosić minimum 1

Person.java

package pl.javastart.model;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Email;

public class Person {
    @NotNull
    private String firstName;
    @NotNull
    private String lastName;
    @Email
    private String email;
    @Min(1)
    private int age;
    
    public Person(String firstName, String lastName, String email, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.age = age;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

A w klasie testowej przeprowadzamy walidację przykładowego obiektu z błędnie ustawionymi wartościami.

ValidationExample.java

package pl.javastart;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import pl.javastart.model.Person;

public class ValidationExample {

    public static void main(String[] args) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        
        //brak nazwiska, błędny email i błędny wiek
        Person person = new Person("Jan", null, "zlyEmail", 0);
        Set<ConstraintViolation<Person>> errors = validator.validate(person);
        errors.forEach(error -> System.err.println(error.getPropertyPath() + " " + error.getMessage()));
    }
}

W konsoli zobaczymy wydruk ze złamanymi ograniczeniami, które są reprezentowane przez obiekty typu ConstraintViolation.

constraint violations

Przykład na Github

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.