AIによる要約
Spring Bootの@Validと@Validatedは、通常の入力検証とグループ指定で使い分けます。特に「@Validated(CreateGroup.class)へ変えたら@NotBlankが効かない」場合は、共通制約のDefaultグループが検証対象に含まれているかを確認してください。登録・更新の入力例と実行結果で違いを確かめます。


Spring Bootで入力チェックを調べると、@Validと@Validatedの両方が出てきます。
普通のFormやRequest DTOを検証するなら@Valid、登録と更新で制約を切り替えるなら@Validatedのグループ指定が候補です。ただし、指定を変えただけで、それまで動いていた名前の必須チェックが外れることがあります。まず使い分けを確認し、次にその見落としを再現します。
この記事のポイント
@Validは標準的なBean Validationの入口として使う@ValidatedはSpringの検証機能で、グループ指定などに使える- 普通のForm入力ならまず
@Validで考える - 既存プロジェクトの方針に合わせることも重要
@Validは標準的な入力チェックとして使う
@Validは、Bean Validationの仕組みを使って、FormクラスやRequest DTOに付けた制約を検証します。
public class UserRegisterForm {
@NotBlank
private String name;
@NotBlank
@Email
private String email;
}
@PostMapping("/users")
public String register(@Valid UserRegisterForm form,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "users/new";
}
userService.register(form);
return "redirect:/users";
}
通常の登録フォームやJSON入力では、まずこの形を理解すれば十分です。必須、桁数、メール形式などの基本的なチェックは@Validで扱えます。
@ValidatedはSpringの検証アノテーション
@ValidatedはSpringが提供する検証用アノテーションです。代表的な使い道は、グループバリデーションです。
import jakarta.validation.groups.Default;
public interface CreateGroup extends Default {}
public interface UpdateGroup extends Default {}
public class UserForm {
@Null(groups = CreateGroup.class)
@NotNull(groups = UpdateGroup.class)
private Long id;
@NotBlank
private String name;
// Formとして受け取るため、getter / setterを用意する
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
上のコードは3ファイル分を続けて示しています。CreateGroup.java、UpdateGroup.java、UserForm.javaへ分けて保存し、それぞれに必要なpackageとimportを付けてください。Defaultのimportは両方のグループに必要です。
登録時はID不要、更新時はID必須、というように同じFormでも処理ごとにチェックを変えたい場合に使われます。
@PostMapping("/users")
public String create(@Validated(CreateGroup.class) UserForm form,
BindingResult bindingResult) {
// 登録用のチェック
return "users/new";
}
@PostMapping("/users/{id}")
public String update(@Validated(UpdateGroup.class) UserForm form,
BindingResult bindingResult) {
// 更新用のチェック
return "users/edit";
}
@Validatedで@NotBlankが効かないときはDefaultを確認する
制約にgroupsを書かない場合、その制約はjakarta.validation.groups.Defaultへ属します。@Validated(CreateGroup.class)のようにグループを指定すると、無関係なDefaultが自動で追加されるわけではありません。
// 修正前:Defaultを継承していない
public interface CreateGroup {}
// この制約はDefaultグループに属する
@NotBlank
private String name;
// CreateGroupだけでは、上のnameは検証対象にならない
@Validated(CreateGroup.class)
上の最後の行はグループ指定を抜き出したものです。修正前の構成で、IDがnull・名前が空文字のFormをCreateGroupだけで検証すると、違反は0件になりました。@NotBlankを削除したり、画面側の必須入力だけに頼ったりせず、前のコードのようにCreateGroupとUpdateGroupをDefaultから継承させます。
グループを継承させない設計なら、@Validated({Default.class, CreateGroup.class})のように両方を明示する方法もあります。ここでは登録・更新の両方に共通の名前チェックが必要なので、継承する方法を採用しました。どちらか一方に統一してください。
登録・更新で実際に検証される項目
検証環境:Java 17.0.8、Spring Boot 3.5.16、Hibernate Validator 8.0.1.Final。以下の入力と結果は、実際にテストして確認したものです。プロジェクトの独自Validatorや例外処理を加えた場合は、その設定でも確認してください。
| 指定グループ | ID | 名前 | 検証結果 |
|---|---|---|---|
| CreateGroup | null | Alice | 違反なし |
| CreateGroup | null | 空文字 | name |
| CreateGroup | 10 | Alice | id |
| CreateGroup | 10 | 空文字 | id・name |
| UpdateGroup | 10 | Alice | 違反なし |
| UpdateGroup | 10 | 空文字 | name |
| UpdateGroup | null | Alice | id |
| UpdateGroup | null | 空文字 | id・name |
表のid・nameは、制約違反が検出されたフィールドです。名前の必須チェックが両方のグループで動くことまで確認します。次は、Springから注入されたValidatorを使うJUnit 5テストの抜粋です。
@Autowired
Validator validator;
@Test
void 登録グループでも空の名前を拒否する() {
UserForm form = new UserForm();
form.setId(null);
form.setName("");
Set<String> fields = validator.validate(form, CreateGroup.class).stream()
.map(v -> v.getPropertyPath().toString())
.collect(Collectors.toSet());
assertThat(fields).containsExactly("name");
}
主なimportはjakarta.validation.Validator、java.util.Set、java.util.stream.Collectors、JUnitのTest、AssertJのassertThatです。テスト依存を含むSpring Bootのテストクラスで実行します。制約のグループ選択と継承の仕様は、Hibernate Validatorの公式資料でも確認できます。
初学者はまず@Validで考える
新人のうちは、いきなり@Validatedやグループバリデーションを使いこなそうとしなくて大丈夫です。普通の入力チェックなら@Validで始める方が読みやすいです。
迷ったら、まず@Valid。登録と更新でチェックを分けたい、メソッド引数を検証したいなど、理由が出てきたら@Validatedを検討します。
importの違いにも注意する
Spring Boot 3系では、@Validはjakarta.validation.Validを使います。古い記事や古いプロジェクトではjavax.validation.Validが出てくることもあります。
import jakarta.validation.Valid; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import org.springframework.validation.annotation.Validated;
プロジェクトのSpring Bootバージョンによってimportが違うため、サンプルをコピペして赤くなったときは、まずimportを確認しましょう。
現場での使い分け
- 単純な画面入力:
@Valid - JSON APIのRequest DTO:
@Valid - 登録と更新でチェックを切り替える:
@Validatedを検討 - Serviceメソッドの引数検証: プロジェクト方針を確認して
@Validatedを検討
使い分けで大事なのは、難しい方を使うことではありません。チームのコードを読んだ人が、なぜそのアノテーションなのか理解できることです。
レビュー前のセルフチェック
確認リスト
- 普通の入力チェックなのに、理由なく
@Validatedを使っていないか - 登録と更新でチェックを分ける必要が本当にあるか
- グループを指定したときも、共通の必須チェックが動くか
- importがプロジェクトのSpring Bootバージョンに合っているか
- 既存コードの入力チェック方針から外れていないか
この記事とあわせて読みたい
まとめ
@Validと@Validatedは、どちらも入力チェックに関係します。初学者は、まず@Validを標準的な入口として理解しましょう。
@Validatedは、グループバリデーションなど明確な理由があるときに使うと考えると、現場コードでも迷いにくくなります。
制約の使い分けが分かったら、エラー表示・入力値の保持・テストまで含めたSpring Bootのフォーム入力・バリデーション実践ガイドで、次に確認する範囲を整理できます。
Springの入力チェックをアプリの流れで学ぶ参考書
フォームの制約、Controllerでの検証、画面へのエラー表示を一つの流れで学びたい人には、『作って学ぶ Spring Boot入門』が候補です。Javaの基本文法、HTML/CSS、基本SQLが前提で、Java未経験者の最初の一冊ではありません。出版社の紹介・目次で、今学びたい範囲と合うか確認できます。




