よくあるエラーとトラブルシューティング
よくあるエラーとトラブルシューティング
Section titled “よくあるエラーとトラブルシューティング”Spring Boot開発でよく遭遇するエラーとその解決方法について、実践的な対処法を解説します。
コンパイルエラー
Section titled “コンパイルエラー”エラー1: パッケージが見つからない
Section titled “エラー1: パッケージが見つからない”エラーメッセージ:
package com.example does not exist原因:
- パッケージ構造が正しくない
- インポート文が間違っている
解決方法:
// 正しいパッケージ宣言package com.example.myapp.service;
// 正しいインポートimport com.example.myapp.model.User;import com.example.myapp.repository.UserRepository;確認事項:
- ファイルのパスがパッケージ名と一致しているか
src/main/java/com/example/myapp/service/UserService.java→package com.example.myapp.service;
エラー2: シンボルが見つからない
Section titled “エラー2: シンボルが見つからない”エラーメッセージ:
cannot find symbol: class UserRepository原因:
- クラスが存在しない
- インポートが不足している
- Lombokのアノテーションが正しく処理されていない
解決方法:
// 1. インポートを確認import com.example.myapp.repository.UserRepository;
// 2. Lombokを使用している場合、IDEでアノテーション処理を有効化// IntelliJ IDEA: Settings → Build → Compiler → Annotation Processors → Enable annotation processing
// 3. Maven/Gradleでクリーンビルド// Maven./mvnw clean compile
// Gradle./gradlew clean build実行時エラー
Section titled “実行時エラー”エラー3: Beanが見つからない(NoSuchBeanDefinitionException)
Section titled “エラー3: Beanが見つからない(NoSuchBeanDefinitionException)”エラーメッセージ:
No qualifying bean of type 'com.example.myapp.service.UserService' available原因:
@Service、@Componentなどのアノテーションが不足- コンポーネントスキャンの対象外
- プロファイルが一致しない
解決方法:
// 1. アノテーションを追加@Service // または @Componentpublic class UserService { // ...}
// 2. コンポーネントスキャンの範囲を確認@SpringBootApplication@ComponentScan(basePackages = "com.example.myapp")public class MyAppApplication { public static void main(String[] args) { SpringApplication.run(MyAppApplication.class, args); }}
// 3. プロファイルを確認@Profile("dev") // プロファイルが一致しているか確認@Servicepublic class DevUserService { // ...}エラー4: 循環依存(Circular Dependency)
Section titled “エラー4: 循環依存(Circular Dependency)”エラーメッセージ:
The dependencies of some of the beans in the application context form a cycle原因:
- クラスAがクラスBに依存し、クラスBがクラスAに依存している
解決方法:
// 悪い例: 循環依存@Servicepublic class UserService { @Autowired private OrderService orderService; // UserService → OrderService}
@Servicepublic class OrderService { @Autowired private UserService userService; // OrderService → UserService(循環)}
// 解決方法1: コンストラクタインジェクション + @Lazy@Servicepublic class UserService { private final OrderService orderService;
public UserService(@Lazy OrderService orderService) { this.orderService = orderService; }}
// 解決方法2: インターフェースを使用public interface UserServiceInterface { User findById(Long id);}
@Servicepublic class UserService implements UserServiceInterface { // ...}
@Servicepublic class OrderService { private final UserServiceInterface userService; // インターフェースに依存
public OrderService(UserServiceInterface userService) { this.userService = userService; }}
// 解決方法3: アーキテクチャの見直し(推奨)// 共通のサービス層を作成するか、イベント駆動アーキテクチャを使用エラー5: トランザクションが機能しない
Section titled “エラー5: トランザクションが機能しない”エラーメッセージ:
Transaction is not active原因:
@Transactionalが適用されていない- 同じクラス内のメソッド呼び出し
- 例外がキャッチされている
解決方法:
// 悪い例: 同じクラス内のメソッド呼び出し@Servicepublic class UserService {
public void createUser(UserCreateRequest request) { saveUser(request); // @Transactionalが効かない }
@Transactional public void saveUser(UserCreateRequest request) { userRepository.save(new User()); }}
// 解決方法1: メソッドを統合@Servicepublic class UserService {
@Transactional public void createUser(UserCreateRequest request) { userRepository.save(new User()); }}
// 解決方法2: 自己注入(非推奨)@Servicepublic class UserService {
@Autowired private UserService self; // プロキシ経由で呼び出す
public void createUser(UserCreateRequest request) { self.saveUser(request); // プロキシ経由なので@Transactionalが効く }
@Transactional public void saveUser(UserCreateRequest request) { userRepository.save(new User()); }}
// 解決方法3: 例外を再スロー@Servicepublic class UserService {
@Transactional public void createUser(UserCreateRequest request) { try { userRepository.save(new User()); } catch (Exception e) { log.error("Error", e); throw e; // 例外を再スローしないとロールバックされない } }}データベース関連エラー
Section titled “データベース関連エラー”エラー6: テーブルが見つからない
Section titled “エラー6: テーブルが見つからない”エラーメッセージ:
Table 'mydb.users' doesn't exist原因:
- テーブルが作成されていない
ddl-auto設定が間違っている- マイグレーションが実行されていない
解決方法:
# 開発環境: 自動でテーブルを作成spring.jpa.hibernate.ddl-auto=create-drop
# 本番環境: マイグレーションツールを使用spring.jpa.hibernate.ddl-auto=validate
# Flywayを使用する場合spring.flyway.enabled=truespring.flyway.locations=classpath:db/migration// エンティティクラスを確認@Entity@Table(name = "users") // テーブル名を明示的に指定public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // ...}エラー7: カラムが見つからない
Section titled “エラー7: カラムが見つからない”エラーメッセージ:
Column 'user_name' doesn't exist原因:
- カラム名の不一致
@Columnアノテーションの設定ミス
解決方法:
@Entity@Table(name = "users")public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
// カラム名を明示的に指定 @Column(name = "user_name", nullable = false, length = 100) private String name;
// スネークケースとキャメルケースの変換設定 // application.properties // spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl}エラー8: 接続エラー
Section titled “エラー8: 接続エラー”エラーメッセージ:
Connection refused. Check that the hostname and port are correct原因:
- データベースサーバーが起動していない
- 接続情報が間違っている
- ファイアウォールの設定
解決方法:
# 接続情報を確認spring.datasource.url=jdbc:postgresql://localhost:5432/mydbspring.datasource.username=myuserspring.datasource.password=mypassword
# 接続タイムアウトを設定spring.datasource.hikari.connection-timeout=30000# データベースサーバーの状態を確認# PostgreSQLpg_isready -h localhost -p 5432
# MySQLmysqladmin ping -h localhost -u root -pHTTP関連エラー
Section titled “HTTP関連エラー”エラー9: 404 Not Found
Section titled “エラー9: 404 Not Found”エラーメッセージ:
404 Not Found原因:
- URLパスが間違っている
- コントローラーのマッピングが間違っている
- コンテキストパスの設定
解決方法:
// コントローラーのマッピングを確認@RestController@RequestMapping("/api/users") // ベースパスpublic class UserController {
@GetMapping("/{id}") // GET /api/users/{id} public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { // ... }}
// application.propertiesでコンテキストパスを確認server.servlet.context-path=/apiデバッグ方法:
@RestController@RequestMapping("/api/users")@Slf4jpublic class UserController {
@GetMapping("/{id}") public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { log.info("GET /api/users/{} called", id); // ログで確認 // ... }}エラー10: 400 Bad Request
Section titled “エラー10: 400 Bad Request”エラーメッセージ:
400 Bad Request原因:
- リクエストボディの形式が間違っている
- バリデーションエラー
- 必須パラメータが不足
解決方法:
// バリデーションエラーの詳細を確認@RestController@RestControllerAdvicepublic class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationException( MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getFieldErrors().forEach(error -> { errors.put(error.getField(), error.getDefaultMessage()); });
ErrorResponse errorResponse = new ErrorResponse( "Validation failed", errors); return ResponseEntity.badRequest().body(errorResponse); }}
// DTOクラスでバリデーションを確認public class UserCreateRequest {
@NotBlank(message = "名前は必須です") @Size(max = 100, message = "名前は100文字以内で入力してください") private String name;
@NotBlank(message = "メールアドレスは必須です") @Email(message = "有効なメールアドレスを入力してください") private String email;}エラー11: 500 Internal Server Error
Section titled “エラー11: 500 Internal Server Error”エラーメッセージ:
500 Internal Server Error原因:
- 未処理の例外
- NullPointerException
- データベースエラー
解決方法:
// グローバル例外ハンドラーを実装@RestControllerAdvice@Slf4jpublic class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { log.error("Unexpected error occurred", ex);
ErrorResponse errorResponse = new ErrorResponse( "Internal server error", ex.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(errorResponse); }
@ExceptionHandler(NullPointerException.class) public ResponseEntity<ErrorResponse> handleNullPointerException( NullPointerException ex) { log.error("NullPointerException occurred", ex);
ErrorResponse errorResponse = new ErrorResponse( "Null pointer exception", "A required value is null"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(errorResponse); }}パフォーマンス関連エラー
Section titled “パフォーマンス関連エラー”エラー12: OutOfMemoryError
Section titled “エラー12: OutOfMemoryError”エラーメッセージ:
java.lang.OutOfMemoryError: Java heap space原因:
- メモリ不足
- 大量のデータ処理
- メモリリーク
解決方法:
# JVMのメモリ設定を変更java -Xms512m -Xmx2048m -jar myapp.jar
# または、application.propertiesで設定(Spring Boot)spring.jvm.arguments=-Xms512m -Xmx2048m// 大量データの処理を最適化@Servicepublic class UserService {
// 悪い例: 全件取得 public List<User> getAllUsers() { return userRepository.findAll(); // メモリ不足の原因 }
// 良い例: ページネーション public Page<User> getAllUsers(Pageable pageable) { return userRepository.findAll(pageable); }
// 良い例: ストリーム処理 @Transactional(readOnly = true) public void processAllUsers() { try (Stream<User> users = userRepository.findAllStream()) { users.forEach(this::processUser); } }}デバッグテクニック
Section titled “デバッグテクニック”ログレベルの変更
Section titled “ログレベルの変更”# デバッグ用にログレベルを変更logging.level.com.example.myapp=DEBUGlogging.level.org.springframework.web=DEBUGlogging.level.org.hibernate.SQL=DEBUGlogging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACEブレークポイントの設定
Section titled “ブレークポイントの設定”@Service@Slf4jpublic class UserService {
public User createUser(UserCreateRequest request) { log.debug("Creating user: {}", request); // ブレークポイントを設定
// 変数の値を確認 User user = new User(); user.setName(request.getName());
return userRepository.save(user); }}スタックトレースの確認
Section titled “スタックトレースの確認”@RestControllerAdvice@Slf4jpublic class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { // スタックトレースをログに出力 log.error("Exception occurred", ex);
// 開発環境ではスタックトレースを含める String message = ex.getMessage(); if (isDevEnvironment()) { message += "\n" + getStackTrace(ex); }
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(new ErrorResponse("Error", message)); }}Jakarta関係のエラー
Section titled “Jakarta関係のエラー”Jakarta EE(旧Java EE)への移行に伴うエラーと解決方法について解説します。
エラー13: パッケージjavaxが見つからない
Section titled “エラー13: パッケージjavaxが見つからない”エラーメッセージ:
package javax.persistence does not existpackage javax.validation does not existpackage javax.servlet does not exist原因:
- Spring Boot 3.x以降では、
javax.*パッケージがjakarta.*に変更された - 古いコードやライブラリが
javax.*を使用している - 依存関係のバージョンがJakarta EEに対応していない
解決方法:
1. インポート文を修正(javax → jakarta):
// ❌ 古いコード(javax.*)import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.GeneratedValue;import javax.validation.constraints.NotNull;import javax.servlet.http.HttpServletRequest;
// ✅ 新しいコード(jakarta.*)import jakarta.persistence.Entity;import jakarta.persistence.Id;import jakarta.persistence.GeneratedValue;import jakarta.validation.constraints.NotNull;import jakarta.servlet.http.HttpServletRequest;2. 主なパッケージ名の変更:
| 旧パッケージ(javax.*) | 新パッケージ(jakarta.*) |
|---|---|
javax.persistence.* | jakarta.persistence.* |
javax.validation.* | jakarta.validation.* |
javax.servlet.* | jakarta.servlet.* |
javax.annotation.* | jakarta.annotation.* |
javax.transaction.* | jakarta.transaction.* |
javax.enterprise.* | jakarta.enterprise.* |
3. 依存関係の更新:
<dependencies> <!-- Spring Boot 3.x以降は自動的にJakarta EEを使用 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.1.0</version> </dependency>
<!-- JPA(Jakarta Persistence) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>3.1.0</version> </dependency>
<!-- Validation(Jakarta Validation) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>3.1.0</version> </dependency></dependencies>dependencies { implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0' implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.1.0' implementation 'org.springframework.boot:spring-boot-starter-validation:3.1.0'}エラー14: クラスが見つからない(NoClassDefFoundError)
Section titled “エラー14: クラスが見つからない(NoClassDefFoundError)”エラーメッセージ:
java.lang.NoClassDefFoundError: javax/persistence/Entityjava.lang.NoClassDefFoundError: javax/validation/constraints/NotNull原因:
- 実行時にJakarta EEのクラスが見つからない
- クラスパスにJakarta EEのライブラリが含まれていない
- 古いバージョンのライブラリが混在している
解決方法:
1. 依存関係の確認:
# Maven: 依存関係ツリーを確認./mvnw dependency:tree | grep -i jakarta./mvnw dependency:tree | grep -i javax
# Gradle: 依存関係を確認./gradlew dependencies | grep -i jakarta./gradlew dependencies | grep -i javax2. 古いライブラリの除外:
<!-- Maven: 古いjavax.*を使用するライブラリを除外 --><dependency> <groupId>com.example</groupId> <artifactId>old-library</artifactId> <version>1.0.0</version> <exclusions> <exclusion> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> </exclusion> </exclusions></dependency>3. クリーンビルド:
# Maven./mvnw clean install
# Gradle./gradlew clean buildエラー15: アノテーションが見つからない
Section titled “エラー15: アノテーションが見つからない”エラーメッセージ:
cannot find symbol: @Entitycannot find symbol: @NotNullcannot find symbol: @Valid原因:
- インポート文が
javax.*のまま - Jakarta EEの依存関係が不足している
- IDEのキャッシュが古い
解決方法:
1. インポート文を修正:
// ❌ 古いコードimport javax.persistence.Entity;import javax.persistence.Id;import javax.validation.constraints.NotNull;import javax.validation.Valid;
// ✅ 新しいコードimport jakarta.persistence.Entity;import jakarta.persistence.Id;import jakarta.validation.constraints.NotNull;import jakarta.validation.Valid;
@Entitypublic class User { @Id private Long id;
@NotNull private String name;}2. IDEのキャッシュをクリア:
IntelliJ IDEA:
File → Invalidate Caches / Restart → Invalidate and RestartEclipse:
Project → Clean → Clean all projects3. 依存関係の確認:
<!-- Maven: Jakarta Persistence API --><dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> <version>3.1.0</version></dependency>
<!-- Jakarta Validation API --><dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>3.0.2</version></dependency>エラー16: Spring Boot 2.xから3.xへの移行エラー
Section titled “エラー16: Spring Boot 2.xから3.xへの移行エラー”エラーメッセージ:
The package javax.persistence is accessible from more than one module原因:
- Spring Boot 2.xと3.xの依存関係が混在している
- モジュールパスでjavax.*とjakarta.*が競合している
解決方法:
1. Spring Bootのバージョンを統一:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.0</version> <!-- 3.x系に統一 --></parent>2. 移行チェックリスト:
// ✅ 移行が必要な主な変更点
// 1. インポート文の変更// javax.* → jakarta.*
// 2. アノテーションの変更// @javax.persistence.Entity → @jakarta.persistence.Entity// @javax.validation.NotNull → @jakarta.validation.NotNull
// 3. 設定ファイルの変更// javax.persistence.* → jakarta.persistence.*
// 4. 依存関係の更新// spring-boot-starter-web:2.7.x → 3.1.0// spring-boot-starter-data-jpa:2.7.x → 3.1.03. 自動移行ツールの使用:
# OpenRewriteを使用した自動移行# https://docs.openrewrite.org/recipes/java/spring/boot3/upgradespringboot_3_0
# Maven./mvnw org.openrewrite.maven:rewrite-maven-plugin:run \ -Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0エラー17: バリデーションアノテーションが動作しない
Section titled “エラー17: バリデーションアノテーションが動作しない”エラーメッセージ:
@NotNull annotation is not recognized@Valid annotation is not recognized原因:
javax.validation.*からjakarta.validation.*への移行が不完全- バリデーションの依存関係が不足している
解決方法:
1. インポート文を修正:
// ❌ 古いコードimport javax.validation.constraints.NotNull;import javax.validation.constraints.NotBlank;import javax.validation.constraints.Email;import javax.validation.Valid;
// ✅ 新しいコードimport jakarta.validation.constraints.NotNull;import jakarta.validation.constraints.NotBlank;import jakarta.validation.constraints.Email;import jakarta.validation.Valid;
public class UserCreateRequest { @NotNull @NotBlank private String name;
@Email private String email;}2. 依存関係の確認:
<!-- Maven: Jakarta Validation --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>3.1.0</version></dependency>3. コントローラーでの使用:
@RestController@RequestMapping("/api/users")public class UserController {
@PostMapping public ResponseEntity<UserDTO> createUser( @Valid @RequestBody UserCreateRequest request) { // @Validはjakarta.validation.Valid // ... }}エラー18: JPAエンティティが認識されない
Section titled “エラー18: JPAエンティティが認識されない”エラーメッセージ:
Not a managed type: class com.example.User原因:
javax.persistence.*からjakarta.persistence.*への移行が不完全- エンティティのアノテーションが古いパッケージを使用している
解決方法:
1. エンティティクラスのインポートを修正:
// ❌ 古いコードimport javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Column;
// ✅ 新しいコードimport jakarta.persistence.Entity;import jakarta.persistence.Id;import jakarta.persistence.GeneratedValue;import jakarta.persistence.GenerationType;import jakarta.persistence.Column;
@Entity@Table(name = "users")public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column(nullable = false) private String name;}2. application.propertiesの確認:
# JPA設定(Jakarta Persistence)spring.jpa.hibernate.ddl-auto=updatespring.jpa.show-sql=truespring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialectJakarta移行のチェックリスト
Section titled “Jakarta移行のチェックリスト”Jakarta EEへの移行時に確認すべき項目:
- すべての
javax.*インポートをjakarta.*に変更 - Spring Boot 3.x以降を使用しているか
- 依存関係がJakarta EEに対応しているか
- IDEのキャッシュをクリアしたか
- クリーンビルドを実行したか
- テストが正常に動作するか
主な変更点の一覧:
| 変更前(javax.*) | 変更後(jakarta.*) |
|---|---|
javax.persistence.Entity | jakarta.persistence.Entity |
javax.persistence.Id | jakarta.persistence.Id |
javax.validation.NotNull | jakarta.validation.NotNull |
javax.validation.Valid | jakarta.validation.Valid |
javax.servlet.http.HttpServletRequest | jakarta.servlet.http.HttpServletRequest |
javax.annotation.PostConstruct | jakarta.annotation.PostConstruct |
javax.transaction.Transactional | jakarta.transaction.Transactional |
よくあるエラーと解決方法:
- コンパイルエラー: パッケージ構造とインポートを確認
- Beanエラー: アノテーションとコンポーネントスキャンを確認
- 循環依存: アーキテクチャの見直しまたは
@Lazyを使用 - トランザクション: メソッド呼び出し方法と例外処理を確認
- データベースエラー: 接続情報とテーブル定義を確認
- HTTPエラー: マッピングとバリデーションを確認
- パフォーマンス: メモリ設定とデータ処理方法を最適化
- Jakarta移行エラー:
javax.*をjakarta.*に変更、依存関係を更新
適切なエラーハンドリングとデバッグテクニックにより、問題を迅速に解決できます。