LoginSignup
1
0

More than 3 years have passed since last update.

Micronaut(Java)でBean Validationを追加する

Last updated at Posted at 2020-03-03

Micronautで自作のBean Validationを使いたい

業務で自作のバリデーターを作る必要が出てきて、新しいフレームワークなので全然資料がない && Java初心者 で結構苦労しました。

結果的には期待する動作をするものが出来たのでメモします。

経緯

現在のタスクで、入力バリデーションとしてよくあるこのような実装が必要になりました。

  1. リクエストの特定のパラメータが、指定の正規表現にマッチしてるか確認
  2. していなければ特定のエラーメッセージを持ったエラーレスポンスを返す

素?のMicronautなら Pattern(regexp = "パターン", message="メッセージ") で実現できると思いますが、現在のプロジェクトではアノテーション別にハンドラで処理をしており、この実装だと不都合でした。

実装

2020/03/04追記 Validatorクラスにに @Singleton を付ける必要があり、加筆しました。

アノテーション + バリデーター

EmployeeNumber フィールドに対して、以下のいずれかを満たしているかチェックするBean Validation

  • 値がNULL
  • UXXXX, NXXX, KXXXX の形
package com.myproject.annotation;

import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.validation.validator.constraints.ConstraintValidator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import javax.validation.Constraint;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.regex.Pattern;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EmployeeNumberValidator.class})
public @interface EmployeeNumber {
    String message() default "社員番号は社名のアルファベット頭文字 + 4桁の半角数字で入力してください。";
}

@Singleton
class EmployeeNumberValidator
implements ConstraintValidator<EmployeeNumber, String> {
    private static final Pattern EmployeeNumberPattern = Pattern.compile("^[UNK]\\d{4}+$");

    @Override
    public boolean isValid(@Nullable String value, @Nonnull AnnotationValue<EmployeeNumber> annotationMetadata, @Nonnull io.micronaut.validation.validator.constraints.ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }
        return EmployeeNumberPattern.matcher(value).matches();
    }
}

今回、 バリデーターとアノテーションをひとまとめにしましたが、別ファイルに切り出したい場合はバリデーターを public にしてアノテーション側で import します。

アノテーション定義インターフェース自体についてるアノテーションは、特にMicronaut固有のものでもなく検索するとすぐ出てくるので解説しません(自分もよくわかってない)

アノテーションを利用するリクエストエンティティ

package com.myproject.request;

import com.myproject.annotation.EmployeeNumber;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import io.micronaut.core.annotation.Introspected;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

@Introspected
@Data
@JsonFormat
public class EmployeeSearchRequest {
    @NotNull
    private String officeCode;
    private String employeeId;
    @EmployeeNumber
    private String employeeName;
}

つまづいたところ

当初、 javax.validation.ConstraintValidator を実装する記事を参考に実装してみたところ、アノテーションはつけられるのに、 ConstraintViolationException のハンドラで拾ってくれない現象が起きました。

io.micronaut.validation.validator.constraints.ConstraintValidator を実装した バリデーターを作成をする必要があったようです。

これを アノテーションの @Constraint に指定することで解決しました。

1
0
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
1
0