17
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Bean Validationで自作バリデータを作る

Last updated at Posted at 2017-10-18

概要

Bean Validationで自作バリデータを書いて、単体テストを書くまでの手順のメモ。

やってみる

試しにマイケルジャクソンの楽曲名かどうかを判定するバリデータを作ってみる。

バリデータクラスの実装

package com.example.customvalidate;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.List;

public class MJValidator implements ConstraintValidator<MJ, String> {

    private final static List<String> songs = new ArrayList<String>() {
        {
            add("Remember The Time"); add("Stranger In Moscow"); add("You Are Not Alone");
        }
    };

    public void initialize(MJ constraintAnnotation) {
    }

    public boolean isValid(String value, ConstraintValidatorContext context) {
        return songs.stream().anyMatch(song -> song.equals(value));
    }
}

解説

  • ConstraintValidatorインタフェースを継承させる。ジェネリクスには、あとで作るアノテーションとバリデーション対象の型を指定する。
  • isValidメソッドで実際のバリデーションの判定を行っている。任意の判定をしてbooleanを返す。
  • 今回の例では、「Remember The Time」か「Stranger In Moscow」か「You Are Not Alone」ならバリデーションが通る。

アノテーションの実装

アノテーションを作る。これで @MJって感じで使えるようになる

package com.example.customvalidate;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = {MJValidator.class})
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MJ {

    String message() default "you must specify one of Michael Jackson's songs.";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        MJ[] value();
    }
}

解説

  • @Constraint(validatedBy=)のところには実際にバリデーションを行うクラスを指定する。上で作ったMJValidatorを指定する。
  • @Targetには、このアノテーションを付与できる対象を指定する。今回は引数とフィールドとした。
  • messageには、バリデーションに引っかかった際に例外オブジェクトに設定されるメッセージを指定する。

テストを書く

package com.example.customvalidate;

import org.junit.Before;
import org.junit.Test;
import javax.validation.*;
import java.util.Set;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

public class MJValidatorTest {

    private Validator validator;

    @Before
    public void setUp() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void 正しくない曲名を渡したときエラーとなること() {
        TestBean bean = new TestBean("Remember a Time");
        Set<ConstraintViolation<Object>> violations = validator.validate(bean);
        assertThat(violations.isEmpty(), is(false));
        String expectedMessage = "you must specify one of Michael Jackson's songs.";
        violations.forEach(v -> assertThat(v.getMessage().equals(expectedMessage), is(true)));
    }

    @Test
    public void 正しい曲名を渡したときエラーとならないこと() {
        TestBean bean = new TestBean("Remember The Time");
        Set<ConstraintViolation<Object>> violations = validator.validate(bean);
        assertThat(violations.isEmpty(), is(true));
    }

    private static class TestBean {
        @MJ
        private String song;

        TestBean(String song) {
            this.song = song;
        }
    }
}

実行して、テストが通っていればok.

解説

  • テストクラスの内部クラスとして適当なクラスを作り、フィールドに今回作ったアノテーションを設定している
  • そのクラスのインスタンスに対してバリデーションを走らせている
17
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?