Java Lambda 関数を使用した「ClassNotFoundException」エラーのトラブルシューティング方法を教えてください。

最終更新日: 2021 年 1 月 7 日

Java で記述された AWS Lambda 関数を実行すると、「ClassNotFoundException」または「NoSuchMethodError」エラーが発生します。これらのエラーを修正するにはどうすればよいですか?

簡単な説明

「ClassNotFoundException」エラーは、 Java ランタイムが完全修飾名でクラスをロードしても、クラスを検索しない場合に発生します。

注: クラスの完全修飾名には、デプロイ パッケージとクラス名が含まれます。

参照する依存関係バージョンがパッケージ化されたバージョンと異なる場合、「NoSuchMethodError」エラーが生成します。

Java 関数のデプロイパッケージの構造については、Java 関数の ZIP デプロイパッケージの作成を参照してください。

解決方法

注: AWS コマンドラインインターフェイス (AWS CLI) コマンドの実行中にエラーが発生する場合は、AWS CLI の最新バージョンを使用していることを確認してください

Java Lambda 関数のデプロイパッケージの構造と内容を確認して、エラーの原因を特定します。ベストプラクティスとして、zipinfo を使用してビルドシステムの出力 Java ファイルを表示します。または、次のいずれかを実行してパッケージをダウンロードできます。

  • AWS CLI から Lambda get-function コマンドを実行します。コマンド出力には、ファイルのダウンロードに使用できる署名付き URL が表示されます。詳細については、Lambda 関数の取得を参照してください。
    注意: このオプションを使用する場合、出力で関数ハンドラー値の設定も確認します。この値は、次の手順で必要になります。
  • Lambda コンソールの関数ページで関数を選択し、以下を実行します。
    [アクション] をクリックします。
    [機能をエクスポート] を選択します。
    [関数をエクスポート] ダイアログボックスで、[デプロイパッケージをダウンロード] を選択します。

次の問題のいずれかを探します。問題を特定して修正したら、Lambda 関数を手動でバンドルしてアップロードします。次に、引き続きエラーが発生するかどうかを確認します。

関数ハンドラーメソッド名を確認

次のいずれかを実行して、Lambda 関数ハンドラーの名前を確認します。

詳細については、Java での AWS Lambda 関数ハンドラーを参照してください。

デプロイパッケージ構造の表示

次のコマンドを実行して、Lambda 関数デプロイパッケージのファイル構造を表示します。

注意: 次のコマンドは Linux/Unix/macOS のシステムにのみ有効です。my-deployment-package.zip をデプロイパッケージのファイル名に置き換えます。

$ zipinfo my-deployment-package.zip

CI/CD パイプラインを使用するときの問題を確認

継続的インテグレーションと継続的デリバリー (CI/CD) パイプラインを使用して関数をパッケージ化してデプロイする場合は、次を確認します。

  • 必要な依存関係はすべて、関数をパッケージ化する時にバンドルされています。
  • 参照される依存関係のバージョンはすべて正しいです。
  • 必要な Amazon Simple Storage Service (Amazon S3) のバケット URL が存在し、ファイルの最新バージョンを指しています。
    注: Amazon S3 バケット URL は、Amazon S3 バケットソースを使用し、バケットのバージョニングが有効になっている場合にのみ必要です。
  • ハンドラー設定の変更をデプロイする前に、コードの変更がデプロイされました。
    注意: Lambda には、1 つのアトミック変更でコードと設定を更新するメカニズムはありません。

クラスファイルの問題を確認

「ClassNotFoundException」エラーという名前のクラスについて、次を確認します。

  • デプロイパッケージに含まれています。クラスが見つからない場合は、デプロイパッケージの作成時にバンドルされていない可能性があります。
  • バンドルされたクラス名は、関数のハンドラー値と同じです。たとえば、関数ハンドラー値が com.amazonaws.lambda.demo.LambdaFunctionHandler の場合、Lambda は関数ディレクトリ「/com/amazonaws/demo/」で「LambdaFunctionHandler.class」のクラス名を想定します。詳細については、Java での AWS Lambda 関数ハンドラーを参照してください。
  • これは、/lib またはルートディレクトリにあります。
  • 場所は Java CLASSPATH 環境変数で指定されます。
  • Lambda レイヤーとして参照されている場合、その内容は java/lib, 以外のディレクトリに抽出されていません。
  • 関数にパッケージ化されたクラスと同じバージョンです。そうでない場合は、ローカルマシンにパッケージしたバージョンとは異なるバージョンがあるかどうかを確認します。

Java 関数のパッケージ化の詳細については、Java の AWS Lambda デプロイパッケージを参照してください。

JAR ファイルの問題を確認

関数がローカルマシン、または AWS サーバーレスアプリケーションモデル (AWS SAM) アプリケーションで正常に実行されるかどうかを確認します。Lambda から呼び出された時にのみ関数が失敗する場合は、参照される依存関係 (JAR ファイル) に問題がある可能性があります。

ヒント: Eclipse 統合開発環境 (IDE) を使用して Java Lambda 関数を構築することを検討してください。Eclipse で使用可能なプラグインを使ってプロジェクトを作成すると、自動的にプロジェクトが適切なビルド用に設定されます。詳細については、AWS Toolkit for Eclipse で Lambda を使用するを参照してください。

ローカルディレクトリに存在し、Java CLASSPATH 環境変数で指定されている JAR ファイルについて、次を確認します。

  • ファイルは関数のデプロイパッケージに含まれています。参照されている JAR ファイルが見つからない場合は、デプロイパッケージの作成時にバンドルされていない可能性があります。
  • ファイルバージョンは、デプロイパッケージ内のファイルと同じです。

ファイルが見つからないか、バージョンが正しくない場合は、すべての依存関係 (JAR ファイル) を /lib またはルートディレクトリにコピーします。正しいバージョンを参照していることを確認してください。次に、圧縮したコンテンツをアップロードします。

注意: Apache Maven や Gradle などのビルドツールを使用している場合は、デプロイアーティファクトのビルド時に必要なプラグインを使用してください。たとえば、Apache Maven シェードプラグインなどです。

Java 関数のパッケージ化の詳細については、Java の AWS Lambda デプロイパッケージを参照してください。

権限問題を確認

Lambda では、zip パッケージファイルにグローバルな読み取り権限が付与される必要があります。詳細については、デプロイパッケージをアップロードするときに Lambda で発生する「権限が拒否されました」または「モジュールをインポートできません」というエラーを解決するには、どうすれば良いですか? を参照してください。