LoginSignup
2
4

More than 3 years have passed since last update.

【ReportAsSingleViolation】そのカスタムバリデーションを車輪の再発明にならないために【既存アノテーションをまとめる】

Posted at

なぜSpring Bootで独自のバリデーションを作りたいの?

API開発を複数人で進めていると、APIで同じ項目が出てきます。

  • 注文番号(orderNo)
  • 商品コード(itmCd)
  • 管理番号(mngNo)
  • ユーザーID(usrId)
  • 等々...

同じ項目であれば、同じアノテーションでバリデーションする事が当たり前。でも、ドキュメントやルールの周知を頑張っても意思疎通がとりきれずアノテーションがズレたものがポロポロと。。

そんなときの解決策の1つとして、カスタムバリデーションがあると思っています。

カスタムバリデーションのパターン

大きく分けて、2つあると思っています。

  • 完全オリジナルなロジックが必要なもの
  • 既存バリデーションの組み合わせで済むレベルのもの

後者を作成するとき、自前でロジックを組んでいませんか?

@ReportAsSingleViolationの利用検討をお勧めいたします。

ReportAsSingleViolation

一言でいうと「アノテーションをまとめるアノテーション」

どうゆうことか、以下ソースの後にポイントを記載します。

UsrId.java
@Documented
@Constraint(validatedBy = {})
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Size(min = 8, max = 10)
@Pattern(regexp = "^[a-zA-Z0-9]*$")
@ReportAsSingleViolation
public @interface UsrId {

    /** エラーが発生した場合のエラーメッセージ. */
    String message() default "ユーザーIDが正しく設定されていません";

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

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

}

Constraint(validatedBy = {})

{}なんです。
やりたいことが既存の組み合わせで完結する場合、ロジックを記述するバリデータークラスは必要ありませんよね。
実際、このカスタムアノテーションはアノテーションの組み合わせだけで完結しています。

message() default "xxx"

@ReportAsSingleViolationを利用するとデフォルトメッセージが機能します。これがすごい。
バリデーション動作時には@Size@Patternそれぞれのメッセージ2つは出力されず、自分が設定したメッセージだけが出力されます。
つまりアノテーションがまとまっているんです。

さいごに

@ReportAsSingleViolationを作ればファイル1つでカスタムバリデーション完成です。

カスタムバリデーションって難しそうだから忙しいし、今のプロジェクトへの適用は後回し。。という固定概念を破壊するくらいの手軽さ。

しかし効果はしっかり発揮します。
サンプルではユーザーID 項目を使う複数のDTOクラスやGETパラメータに以下がバラまかれるのを防ぎました。
- @Size(min = 8, max = 10)
- @Pattern(regexp = "^[a-zA-Z0-9]*$")

ルールとして@UsrIdを使おう!というのは必要になります。ですが、特定の引数を付けたバリデーション利用を徹底してください。というルールよりはマシではないか思っています。

是非お試しくださいませ。

2
4
1

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
2
4