独自バリデーション向けアノテーションを作成
バリデーションに使うアノテーションを自作します。
事前準備
下記依存関係を追加します:
<!-- Source: https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.1.1</version>
<scope>compile</scope>
</dependency>
<!-- Source: https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>4.0.6</version>
<scope>compile</scope>
</dependency>
単一パラメータに関わるバリデーション
指定したパラメータが特定の値であるかをチェックするアノテーションを作成します。
- アノテーション
package nob.example.easyapp.validator;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
/**
* サンプルのバリデーションです。
*
* @author nob
*/
@Documented
@Constraint(validatedBy = SampleValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Sample {
/** エラーメッセージ */
String message() default "バリデーションエラーが発生しました。";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- バリデーションの実装
package nob.example.easyapp.validator;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class SampleValidator implements ConstraintValidator<Sample, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// ユーザ名"nob"は許可しない
return !value.equals("nob");
}
}
複数パラメータに関わるバリデーション
2つの日付の前後関係をチェックするアノテーションを作成します。
- アノテーション
package nob.example.easyapp.validator;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
/**
* サンプルのバリデーションです。
*
*/
@Documented
@Constraint(validatedBy = { SampleValidator.class }) // バリデータクラスを指定
@Target({ ElementType.TYPE }) // クラスに対して付与することを宣言
@Retention(RetentionPolicy.RUNTIME)
public @interface Sample {
/** 開始日 */
String startDate();
/** 終了日 */
String endDate();
/** エラーメッセージ */
String message() default "サンプルエラー";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- バリデーションの実装
package nob.example.easyapp.validator;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
* サンプルのバリデータクラスです。
*
*/
@NoArgsConstructor
@AllArgsConstructor
public class SampleValidator implements ConstraintValidator<Sample, Object> {
/** 開始日 */
private String startDate;
/** 終了日 */
private String endDate;
@Override
public void initialize(Sample annotation) {
this.startDate = annotation.startDate();
this.endDate = annotation.endDate();
}
/**
* 今回はクラスに対するアノテーションなので、第一引数の型をObjectとして、各フィールドの値が格納されるようにしています。
* フィールドに対して付与するアノテーションの場合、例えばString型にすることでそのフィールドの値が格納されます。
*
*/
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
String startDateStr = (String) beanWrapper.getPropertyValue(startDate);
String endDateStr = (String) beanWrapper.getPropertyValue(endDate);
boolean result = false;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
Date startDate = simpleDateFormat.parse(startDateStr);
Date endDate = simpleDateFormat.parse(endDateStr);
// 開始日が終了日より前か同日であればOK
if (startDate.compareTo(endDate) <= 0) {
return true;
}
} catch (ParseException e) {
// 日付の形式が不正な場合はチェックしない
return true;
}
return result;
}
}
- テストクラス
package nob.example.easyapp.validator;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* SampleValidatorのテストクラスです。
*
* @author nob
*/
public class SampleValidatorTest {
@Test
public void test() {
SampleValidator sampleValidator = new SampleValidator("startDate", "endDate");
assertTrue(sampleValidator.isValid(new SampleValidatorTestDto("2024-07-01", "2024-07-02"), null));
assertFalse(sampleValidator.isValid(new SampleValidatorTestDto("2024-07-03", "2024-07-02"), null));
}
/**
* SampleValidatorのテスト用dtoです。
*
* @param startDate 開始日
* @param endDate 終了日
*/
private record SampleValidatorTestDto(String startDate, String endDate) {
}
}