SpringBootでバリデーション処理を自作する方法

SpringBootでバリデーション処理を自作する方法

SpringBootでバリデーション処理を自作する方法について、以下の手順とコード例を示します。
ここでは、カスタムバリデータを作成し、SpringBootのバリデーションフレームワークと統合する方法を解説します。

1. バリデータアノテーションの作成

まず、自作のバリデータを定義するために、アノテーションを作成します。
このアノテーションは、バリデーションを適用するフィールドに付けるものです。

@CustomConstraint アノテーションの作成
package com.example.validation;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = CustomValidator.class)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomConstraint {
  String message() default "Invalid value";

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

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

2. バリデータの実装

次に、アノテーションで指定したバリデータを実装します。
ConstraintValidator インターフェースを実装し、バリデーションロジックを定義します。

CustomValidator クラスの作成
package com.example.validation;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class CustomValidator implements ConstraintValidator<CustomConstraint, String> {

  @Override
  public void initialize(CustomConstraint constraintAnnotation) {
    // 初期化コードがあればここに記述します
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    // バリデーションロジックを実装します
    if (value == null || value.trim().isEmpty()) {
      return false;
    }
    // 例えば、特定の文字列パターンに合致するか確認するなど
    return value.matches("^[a-zA-Z0-9]+$");
  }
}

3. バリデーションアノテーションの使用

作成したバリデーションアノテーションを、モデルクラスのフィールドに適用します。

モデルクラスの例
package com.example.model;

import com.example.validation.CustomConstraint;

public class User {

  @CustomConstraint
  private String username;

  // getters and setters
  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }
}

4. バリデーションエラーハンドリング

バリデーションエラーが発生した場合にエラーメッセージを処理するためのエラーハンドリングを設定します。
SpringBootでは、通常は @ControllerAdvice を使用して全体的なエラーハンドリングを行います。

エラーハンドリングの実装
package com.example.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
    Map<String, String> errors = new HashMap<>();
    ex.getBindingResult().getAllErrors().forEach((error) -> {
      String fieldName = ((FieldError) error).getField();
      String errorMessage = error.getDefaultMessage();
      errors.put(fieldName, errorMessage);
    });
    return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
  }
}

5. テスト

バリデーションが正しく機能するかをテストします。
JUnitを使用して、バリデーションのチェックを行うテストケースを作成できます。

テストクラスの例
package com.example;

import com.example.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.ConstraintViolation;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class UserValidationTest {

  private final Validator validator;

  public UserValidationTest() {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    validator = factory.getValidator();
  }

  @Test
  public void testValidUser() {
    User user = new User();
    user.setUsername("validUser123");
    Set<ConstraintViolation<User>> violations = validator.validate(user);
    assertTrue(violations.isEmpty());
  }

  @Test
  public void testInvalidUser() {
    User user = new User();
    user.setUsername("invalid user!");
    Set<ConstraintViolation<User>> violations = validator.validate(user);
    assertEquals(1, violations.size());
    assertEquals("Invalid value", violations.iterator().next().getMessage());
  }
}

この手順に従って、SpringBootで自作のバリデーション処理を実装することができます。
必要に応じて、バリデーションロジックやエラーハンドリングをカスタマイズしてください。