Spring Bootで入力チェックを書くと、`@Valid`と`@Validated`のどちらを使うか迷うことがあります。通常のBean Validationなら`@Valid`で十分な場面が多く、Validation Groupsを明示して検証対象を切り替えたいときはSpringの`@Validated`が使いやすい、というのが基本の判断です。
まず比較:@Validと@Validatedの違い
| 観点 | @Valid | @Validated |
|---|---|---|
| 提供元 | Jakarta Validation | Spring Framework |
| 基本Validation | できる | できる |
| Validation Groups指定 | Annotation自体では指定しない | valueでGroupを指定できる |
| ネストObjectのcascade | 主な用途の1つ | 必要に応じて@Validと組み合わせる |
| 典型用途 | 通常の入力Object検証 | Groupを切り替える検証・Springのmethod validation |
Spring MVCでは、`@RequestBody`などのmethod parameterに`@Valid`または`@Validated`を付けるとStandard Bean Validationを適用できます。違いが大きく出るのは、Validation Groupを使うときです。
@ValidはJakarta Validationの標準Annotation
`@Valid`はSpring固有ではなくJakarta Validation側のAnnotationです。Controllerの入力ObjectやネストしたObjectへValidationを伝播させる用途で使われます。
public record CreateUserRequest(
@NotBlank String name,
@Email String email
) {}
@PostMapping("/users")
public void create(@Valid @RequestBody CreateUserRequest request) {
// validation passed
}
(まず@Validを使ったSpring Bootの基本Validationを確認したい場合については『Spring Bootのフォームバリデーションとは?@Validで安全な入力チェックを実現しよう』をご参照ください)
@ValidatedはSpringのAnnotationでGroupsを指定できる
`@Validated`はSpring FrameworkのAnnotationです。Springの`SmartValidator`へvalidation hintを渡す仕組みを使い、Validation Groupのclassを指定できます。登録時と更新時で検証ルールを変えるようなケースで便利です。
public interface CreateGroup {}
public interface UpdateGroup {}
public class UserRequest {
@NotBlank(groups = CreateGroup.class)
private String name;
@NotNull(groups = UpdateGroup.class)
private Long id;
}
@PostMapping("/users")
public void create(
@Validated(CreateGroup.class) @RequestBody UserRequest request
) {
}
@PutMapping("/users/{id}")
public void update(
@Validated(UpdateGroup.class) @RequestBody UserRequest request
) {
}
Validation Groupsは『同じDTOの検証条件を切り替える』仕組み
Jakarta Validationでは、各constraintを1つ以上のGroupへ所属させられます。Groupを指定しないconstraintはDefault groupに属します。Create/Updateのように状態ごとに必要なconstraintが違う場合、Groupを使って検証対象を切り替えられます。
| ケース | 向く方法 |
|---|---|
| 全操作で同じconstraint | Default group + @Valid |
| 作成時だけ必須 | CreateGroup + @Validated |
| 更新時だけ必須 | UpdateGroup + @Validated |
| ネストObjectも検証 | @Validによるcascadeを確認 |
Controllerではmethod validationとの違いにも注意する
Spring MVCの現行仕様では、Request ObjectのValidationと、method parameterへ直接`@NotBlank`や`@Min`などを付けるmethod validationは別の経路です。直接constraintがある場合はmethod validationが適用され、`HandlerMethodValidationException`が使われるケースがあります。
またSpring Framework 6.1以降のMVC built-in method validationを使うControllerでは、class-levelの`@Validated`を外すよう公式ドキュメントで案内されています。Service層などAOPを使うmethod validationとは区別して考えます。
よくある混同:@Validatedに変えればValidationが直るわけではない
Validationが効かない原因がdependency不足、constraintの付け忘れ、BindingResultの扱い、method signatureなどにある場合、`@Valid`を`@Validated`へ置き換えるだけでは解決しません。Groupsが必要なのか、そもそもValidationが発火していないのかを分けて確認します。
(Validation自体が動かない場合の確認ポイントについては『Spring Boot バリデーション効かない?5分で直す方法』をご参照ください)
使い分けの判断基準
- 通常のRequest Object検証ならまず@Valid
- Create/UpdateなどGroupを指定するなら@Validated(Group.class)
- ネストObjectのcascadeは@Validの有無を確認
- Controllerのmethod parameterへ直接constraintを置く場合はmethod validationの例外経路も確認
- Annotationを変える前に、何を切り替えたいのかを明確にする
現在のDTOでCreateとUpdateのconstraintが混在しているなら、まずGroupに分ける必要があるかを確認してから`@Validated`を導入してみてください。