はじめに (対象読者・この記事でわかること)

この記事は、以下のような読者を対象としています。

  • Spring BootでWebアプリケーションを開発している方
  • Spring Bootのバージョンアップを検討している、または実施した方
  • 特にSpring Boot 2.3.0以降へのアップデートで、Unresolved reference: validationといったエラーに遭遇し困っている方

この記事を読むことで、Spring Boot 2.3.0以降へのバージョンアップでjavax.validation関連のエラーが発生する原因とその具体的な解決策を理解し、安全かつスムーズにアプリケーションのバリデーション機能を維持できるようになります。実際にこの問題に直面した筆者の経験に基づき、エラー解決までの道のりを共有します。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • Javaの基本的なプログラミング知識
  • Spring Bootを使用したWebアプリケーション開発の基本的な経験
  • MavenまたはGradleといったビルドツールの基本的な利用経験

Spring BootとValidation:バージョンアップにおける依存関係の変更

Spring Bootアプリケーションにおいて、ユーザーからの入力データが正しい形式であるかを検証する「バリデーション(Validation)」は、セキュリティとデータ整合性を保つ上で不可欠な機能です。Spring Bootでは、Bean Validation(JSR 380: Bean Validation 2.0) APIをjavax.validationパッケージを通じて標準的にサポートしており、@NotNull, @Size, @Patternなどのアノテーションを使って簡単にバリデーションを実装できます。

しかし、Spring Bootのバージョンが上がるにつれて、特に2.3.0以降では、このバリデーション関連の依存関係の取り扱いが変更されました。以前のバージョンでは、spring-boot-starter-webをプロジェクトに追加するだけで、裏側でBean Validationの実装(一般的にはHibernate Validator)も自動的に組み込まれていました。これにより、開発者は特に意識することなくjavax.validationのアノテーションを利用できました。

ところが、Spring Boot 2.3.0以降では、この暗黙的な依存関係が削除されました。これは、アプリケーションの実行時フットプリントを削減し、不要な依存関係を含まないようにするための設計変更の一環です。もしアプリケーションがバリデーションを使用しない場合、その依存関係を含まないことで、より軽量なアプリケーションを構築できるようになります。この変更は、特に既存のプロジェクトをバージョンアップする際に、Unresolved reference: validationのようなエラーとして顕在化することがあります。

次のセクションでは、この具体的なエラーの発生状況と、どのように解決するかを詳細に解説します。

Unresolved reference: validationエラーの原因と具体的な解決策

Spring Boot 2.3.0以降へのバージョンアップ後、プロジェクト内でjavax.validationパッケージに属するクラス(例: javax.validation.Valid, javax.validation.constraints.NotNullなど)を使用している箇所で、IDEが「Unresolved reference: validation」というエラーを表示したり、ビルド時に「package javax.validation does not exist」のようなコンパイルエラーが発生したりする場合があります。これはまさに、前述した依存関係の変更が原因です。

エラーの具体的な発生状況

例えば、以下のようなコントローラーやデータ転送オブジェクト(DTO)で@Valid@NotNullなどのバリデーションアノテーションを使用しているとします。

Java
import javax.validation.Valid; // ここでUnresolved reference: validation import javax.validation.constraints.NotNull; // ここでも同様 import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @PostMapping("/api/items") public String createItem(@RequestBody @Valid ItemRequest request) { // @Validでエラー // 処理 return "Item created: " + request.getName(); } } class ItemRequest { @NotNull // @NotNullでエラー private String name; private int quantity; // Getter, Setter public String getName() { return name; } public void setName(String name) { this.name = name; } public int getQuantity() { return quantity; } public void setQuantity(int quantity) { this.quantity = quantity; } }

このコードはSpring Boot 2.2.x以前では問題なくコンパイルできていたのに、2.3.0以上にバージョンアップすると、javax.validationパッケージが見つからないためにコンパイルエラーとなります。

ハマった点やエラー解決 (原因究明)

筆者がこの問題に直面した際、最初に考えたのは「IDEがおかしいのか?」「キャッシュが壊れたのか?」といったことでした。クリーンビルドやIDEの再起動、プロジェクトのインポートし直しなどを試しましたが、一向に解決しません。

次に、Spring Bootのリリースノートや移行ガイドを丹念に確認し始めました。そこで見つけたのが、Spring Boot 2.3.0で導入された以下の変更点です。

spring-boot-starter-webからspring-boot-starter-validationの分離

Spring Boot 2.3.0のリリースノートには、以下のような記述があります。

Validation Starter No Longer Pulled In By Web Starter The spring-boot-starter-validation is no longer pulled in by the spring-boot-starter-web and spring-boot-starter-webflux starters. If you are using Spring MVC or Spring WebFlux and want to use validation, you'll now need to add spring-boot-starter-validation as a dependency.

これはまさに今回のエラーの原因を指し示しています。つまり、spring-boot-starter-webを使用している場合でも、バリデーション機能が必要ならば、明示的にspring-boot-starter-validationを追加する必要があるということです。

この変更により、spring-boot-starter-validationが提供していたhibernate-validatorjakarta.validationjavax.validation)といった依存関係が自動的に組み込まれなくなり、既存のコードでこれらのクラスを参照している場合に「Unresolved reference」エラーが発生するのです。

解決策

解決策は非常にシンプルです。プロジェクトのビルドファイル(pom.xmlまたはbuild.gradle)にspring-boot-starter-validationを依存関係として追加します。

Mavenの場合 (pom.xml)

<dependencies>セクションに以下のdependencyを追加してください。

Xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <!-- ここはあなたのプロジェクトのバージョンに合わせる --> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>myproject</artifactId> <version>0.0.1-SNAPSHOT</version> <name>myproject</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- ★ここを追加★ --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- ★ここまで★ --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

追加後、Mavenの依存関係を再読み込み(IntelliJ IDEAであればMavenタブから「Reload All Maven Projects」)し、プロジェクトをクリーンビルドしてください。

Bash
# プロジェクトルートで実行 mvn clean install

Gradleの場合 (build.gradle)

dependenciesブロックに以下のimplementation依存関係を追加してください。

Gradle
plugins { id 'org.springframework.boot' version '2.3.12.RELEASE' // ここはあなたのプロジェクトのバージョンに合わせる id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' // ★ここを追加★ implementation 'org.springframework.boot:spring-boot-starter-validation' // ★ここまで★ testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } } test { useJUnitPlatform() }

追加後、Gradleの依存関係を再読み込み(IntelliJ IDEAであればGradleタブから「Reload All Gradle Projects」)し、プロジェクトをクリーンビルドしてください。

Bash
# プロジェクトルートで実行 ./gradlew clean build

これらの手順を実行することで、javax.validation関連のクラスが再びクラスパスに追加され、Unresolved reference: validationエラーが解消されるはずです。IDEのキャッシュが原因でまだエラーが表示される場合は、IDEを再起動するか、キャッシュをクリアして再インデックス化することを試みてください。

これで、バージョンアップ後もこれまで通りBean Validationを利用できるようになります。

まとめ

本記事では、Spring Bootを2.3.0以降にバージョンアップした際に発生するUnresolved reference: validationエラーの原因と解決策について解説しました。

  • Spring Boot 2.3.0以降では、spring-boot-starter-webからspring-boot-starter-validation依存関係が削除されました。
  • その結果、以前は暗黙的に提供されていたjavax.validation関連のクラスがクラスパスからなくなり、Unresolved reference: validationなどのコンパイルエラーが発生します。
  • この問題は、Mavenプロジェクトであればpom.xmlに、Gradleプロジェクトであればbuild.gradlespring-boot-starter-validationを明示的に追加することで解決できます。

この記事を通して、Spring Bootのバージョンアップ時に直面する可能性のある共通の落とし穴とその回避方法を理解し、より安定した開発環境を維持する手助けになれば幸いです。バージョンアップは新しい機能や改善をもたらしますが、同時に依存関係の変更による問題も発生し得るため、公式ドキュメントやリリースノートの確認が重要であることを改めて認識いただけたかと思います。

今後は、Bean Validationのより高度な使い方や、カスタムバリデーションの実装など、さらに踏み込んだ内容についても記事にする予定です。

参考資料