Serverless Framework+AWS Lambda(Java8)でHello worldしようとしたらNoClassDefFoundError
少しずつですがJavaのビルドツール周りも分かりかけてきたなという矢先、エラーで数時間ハマりました…😭
開発環境
- OS: Windows11 Home 21H2
$ node -v
v16.14.2
$ npm -v
8.5.0
$ sls --version
Framework Core: 2.34.0
Plugin: 4.5.3
SDK: 4.2.2
Components: 3.8.2
$ java --version
openjdk 17.0.2 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
$ aws --version
aws-cli/2.1.19 Python/3.7.9 Windows/10 exe/AMD64 prompt/off
経緯
- Serverless Frameworkのテンプレート
aws-java-mavenを使って、プロジェクトを新規作成。(sls create -t aws-java-maven) pom.xmlに記載のライブラリに脆弱性のあるものが含まれているとIDEに怒られていた為、バージョンを修正。(かの有名なlog4jの脆弱性修正前のバージョンがテンプレートとして使われていました。これ普通に危ない…。)mvn install,mvn packageでビルド。sls deployでAWS Lambdaへデプロイを実行。結果は成功。- ローカルから
sls invokeを実行し、Lambdaのテストをしてみたが下記のエラーが発生。
$ sls invoke -f hello
{
"errorMessage": "com/fasterxml/jackson/core/util/JacksonFeature",
"errorType": "java.lang.NoClassDefFoundError",
"stackTrace": [
"com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:673)",
"com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:576)",
"com.serverless.ApiGatewayResponse$Builder.<clinit>(ApiGatewayResponse.java:53)",
"com.serverless.ApiGatewayResponse.builder(ApiGatewayResponse.java:46)",
"com.serverless.Handler.handleRequest(Handler.java:20)",
"com.serverless.Handler.handleRequest(Handler.java:12)"
],
"cause": {
"errorMessage": "com.fasterxml.jackson.core.util.JacksonFeature",
"errorType": "java.lang.ClassNotFoundException",
"stackTrace": [
"java.net.URLClassLoader.findClass(URLClassLoader.java:387)",
"java.lang.ClassLoader.loadClass(ClassLoader.java:418)",
"java.lang.ClassLoader.loadClass(ClassLoader.java:351)",
"com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:673)",
"com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:576)",
"com.serverless.ApiGatewayResponse$Builder.<clinit>(ApiGatewayResponse.java:53)",
"com.serverless.ApiGatewayResponse.builder(ApiGatewayResponse.java:46)",
"com.serverless.Handler.handleRequest(Handler.java:20)",
"com.serverless.Handler.handleRequest(Handler.java:12)"
]
}
}
...
エラー発生時点のpom.xml
上述のエラー発生前にlog4j-core, jackson-databindに脆弱性があるとIDEから指摘されていた為、推奨のバージョンに修正をしていましたが、どうもこれではうまく動作しませんでした。
...
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j2</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<!-- ↓バージョン変更箇所 -->
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<!-- ↓バージョン変更箇所 -->
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.10</version>
</dependency>
</dependencies>
...
原因
pom.xmlの依存関係にあるライブラリ同士のバージョンに差異があり、実行時にエラーが発生していた。
具体的には以下のように修正をすることで、正常にLambdaが動作しました。
対応
pom.xmlの修正
groupIdが同じライブラリ同士は、バージョンを揃えてあげる必要があったようで、今回はorg.apache.logging.log4j, com.fasterxml.jackson.coreを修正しました。
...
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j2</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.2</version>
</dependency>
</dependencies>
...
再度デプロイ
pom.xmlを修正したらもう1度ビルド+デプロイを実行。
$ mvn install
$ mvn package
$ sls deploy
動作のテスト
$ sls invoke -f hello
{
"statusCode": 200,
"body": "{\"message\":\"Go Serverless v1.x! Your function executed successfully!\",\"input\":{}}",
"headers": {
"X-Powered-By": "AWS Lambda & serverless"
},
"isBase64Encoded": false
}
JSONのレスポンスが返ってきました!どうやらLambdaが正しく動作してくれたようです😊
Node.jsでも依存関係で辛いことがたまにありますが、Javaでも注意が必要ですね。