Easy input check with Bean Validation!

1.First of all

This time, I would like to explain the input check method using Bean Validation.

2. Preparation of library

Add the required libraries to the dependencies. javax.el is also added as it is needed for message resolution of hibernate-validator. The Bean Validation library (groupId: javax.validation, artifactId: validation-api) is not described, but it is automatically added to the dependency because it has a dependency.

pom.xml


  <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.9.Final</version>
  </dependency>
  <dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.el</artifactId>
    <version>3.0.1-b09</version>
  </dependency>

3. Model definition

Define the model class to be checked. At this time, annotate according to each check is added. The following three types of annotations can be added.

Some checks require a limit, such as @ Max, which limits the maximum number, but this is set as an annotation attribute. The attributes that can be set differ for each annotation. If you want to change the message displayed when the check fails, override it with the message attribute. The message set in the message attribute has the highest priority.

Book.java


package com.example.beanvalidation.app;

import java.io.Serializable;
import java.util.Date;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

public class Book implements Serializable {

    private static final long serialVersionUID = 1L;

    @NotNull
    // @Pattern(regexp = "[0-9,-]+")
    @Pattern(regexp = "[0-9,-]+", message = "Value entered${validatedValue}Is incorrect. Please enter in ISBM format.")
    private String isbn;

    @NotNull
    @Size(max = 200)
    private String title;

    @Max(9999)
    @Min(1)
    private int pageCount;

    @NotNull
    @Past
    private Date publishedDate;

    // constructor, setter, getter omitted
}

4. Change error message

Bean Validation is an implementation library-dependent error message for the specification. In this case, the message defined by hibernate-validator will be the default. If you want to change this default message, you can override it with ValidationMessages.properties located directly under the classpath.

This time I would like to change the default message of @ Past.

Validation Messages directly under the classpath_ja.properties (for Japanese)


# javax.validation.constraints.Past.message=Date entered${validatedValue}Is incorrect. Please enter a past date.
javax.validation.constraints.Past.message=\u5165\u529B\u3055\u308C\u305F\u65E5\u4ED8 ${validatedValue} \u306F\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002\u904E\u53BB\u65E5\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002

(Caution)

5. Basic usage

I would like to set various values for the Book class defined above and actually perform an input check. It is common to inject Validator when using a DI container, but this time we will use a normal Java application with a main method. However, the usage of Validator is the same.

ValidationDemo.java


package com.example.beanvalidation.app;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Set;

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

public class ValidationDemo {

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

        // 2. create target object
        Book book = createBook();

        // 3. validate
        Set<ConstraintViolation<Book>> constraintViolations = validator
                .validate(book);

        // 4. check result
        int errorCount = constraintViolations.size();
        System.out.println("validate error count : " + errorCount);
        if (errorCount > 0) {
            showErrorDetails(constraintViolations);
        }

        System.out.println("=== demo : validate error ===");
        
        // 2. create target object
        book = createNgBook();

        // 3. validate
        constraintViolations = validator.validate(book);

        // 4. check result
        errorCount = constraintViolations.size();
        System.out.println("validate error count : " + errorCount);
        if (errorCount > 0) {
            showErrorDetails(constraintViolations);
        }
    }

    private static <T> void showErrorDetails(
            Set<ConstraintViolation<T>> constraintViolations) {
        for (ConstraintViolation<T> violation : constraintViolations) {
            System.out.println("----------");
            System.out.println(
                    "MessageTemplate : " + violation.getMessageTemplate());
            System.out.println("Message : " + violation.getMessage());
            System.out.println("InvalidValue : " + violation.getInvalidValue());
            System.out.println("PropertyPath : " + violation.getPropertyPath());
            System.out.println("RootBeanClass : " + violation.getRootBeanClass());
            System.out.println("RootBean : " + violation.getRootBean());
        }
    }

    private static Book createBook() {
        Date publishedDate = Date.from(LocalDateTime.of(2017, 7, 21, 0, 0, 0)
                .toInstant(ZoneOffset.ofHours(9)));
        return new Book("978-4798142470",
                "Thorough introduction to Spring Java application development with Spring Framework", 744,
                publishedDate);
    }

    private static Book createNgBook() {
        Date publishedDate = Date.from(LocalDateTime.of(2999, 7, 21, 0, 0, 0)
                .toInstant(ZoneOffset.ofHours(9)));
        return new Book("ERROR-ISBN-9999", null, 0, publishedDate);
    }
}

6. Execution result (bonus)

For reference, the result of executing the above program is shown below.

Execution result


validate error count : 0
=== demo : validate error ===
validate error count : 4
----------
MessageTemplate : {javax.validation.constraints.Min.message}
Message : must be greater than or equal to 1
InvalidValue : 0
PropertyPath : pageCount
RootBeanClass : class com.example.beanvalidation.app.Book
RootBean : Book [isbn=ERROR-ISBN-9999, title=null, pageCount=0, publishedDate=Sun Jul 21 00:00:00 JST 2999]
----------
MessageTemplate : {javax.validation.constraints.Past.message}
Message :Date entered Sun Jul 21 00:00:00 JST 2999 is incorrect. Please enter a past date.
InvalidValue : Sun Jul 21 00:00:00 JST 2999
PropertyPath : publishedDate
RootBeanClass : class com.example.beanvalidation.app.Book
RootBean : Book [isbn=ERROR-ISBN-9999, title=null, pageCount=0, publishedDate=Sun Jul 21 00:00:00 JST 2999]
----------
MessageTemplate : {javax.validation.constraints.NotNull.message}
Message : must not be null
InvalidValue : null
PropertyPath : title
RootBeanClass : class com.example.beanvalidation.app.Book
RootBean : Book [isbn=ERROR-ISBN-9999, title=null, pageCount=0, publishedDate=Sun Jul 21 00:00:00 JST 2999]
----------
MessageTemplate :Value entered${validatedValue}Is incorrect. Please enter in ISBM format.
Message :Entered value ERROR-ISBN-9999 is incorrect. Please enter in ISBM format.
InvalidValue : ERROR-ISBN-9999
PropertyPath : isbn
RootBeanClass : class com.example.beanvalidation.app.Book
RootBean : Book [isbn=ERROR-ISBN-9999, title=null, pageCount=0, publishedDate=Sun Jul 21 00:00:00 JST 2999]

7. Finally

This time, I explained how to check the input by Bean Validation. I think it's simple and easy to understand because you can define the input check specifications just by adding the check annotation.

Recommended Posts

Easy input check with Bean Validation!
Add Bean Validation with Micronaut (Java)
Create your own validator with Bean Validation
Phone number input check
[Java] Correlation check without creating annotations by Bean Validation
JSON validation with JSON schema
Self-made Validation with Spring
Easy BDD with (Java) Spectrum?
Easy microservices with Spark Framework!
Bean mapping with MapStruct Part 1
Check compliance with object-oriented exercise
Check CSV value with RSpec
Process validation messages with Decorator
Bean mapping with MapStruct Part 3
Bean mapping with MapStruct Part 2
Integer check method with ruby
Check performance quickly with irb
Easy web scraping with Jsoup
Easy library introduction with Maven!
Exciting environment check with mkmf