最近、仕事でNoClassDefFoundErrorが発生して地味に手こずったので、解決方法の1例を紹介します。
まず、NoClassDefFoundErrorの概要について少しだけ。
NoClassDefFoundErrorはJavaにおける基礎的なErrorの1つです。
ClassNotFoundExceptionとの違いは「まじでやべぇかどうか」です。まぁExceptionとErrorだとErrorの方がやべぇんでw
なので、明確な違いはないと思って良いです。個人的なイメージは、NoClassDefFoundErrorはビルド→実行のプロセスに何かしら問題があるとき、ClassNotFoundExceptionはリフレクション等を使用してクラスにアクセスしようとして、クラス名がミスってたりでアクセスできなかったときに発生するイメージです。
で、このJavaの基礎的な部分であるNoClassDefFoundErrorに手こずったと。
私の今の現場での開発環境では、Eclipse上でTomcatを動かすことができません。(多分頑張ればできるんだろうけど。)デバッグしたい場合は、Antでビルドして、コマンドプロンプトからアプリケーションを起動して、Eclipseの[デバッグの構成]からソースとアプリケーションを紐づけます。
Ant…古い…まぁリプレース案件の古い側のシステムだからまぁいいか…。
こういった環境の場合、依存関係の整合性が上手くいかない場合があります。普通はEclipseがclassファイルとjarをいい感じにTomcatに上げてくれるもんなんですがねぇ…。
で、この辺で躓いたと。
私は「デバッグ時にオブジェクトをJSON形式に変換したいなー」と思っていて、Jacksonライブラリを依存関係に追加しようとしていました。
の2つを追加しました。
そして、アプリケーションを実行して、Eclipseの式タブでjackson-databind.jarに内包されているObjectMapperにアクセスしようとしたら、NoClassDefFoundErrorが発生しました。
この根本原因自体はシンプルなものでした。
普通にネット上でjacksonの使い方の記事を漁れば解決出来た話でしたw
ただただjarが足りていませんでした。
jackson-databind.jarのモジュールを使用したい場合、jackson-annotations.jarも追加する必要があるという、それだけの話でした。
ただ、環境が複雑で考えられる原因が多く、なかなかその答えに行き着くことができませんでした。
根本の原因は分かりましたが、じゃあ自分に何の知識が足りていなくて、何をしていたらすぐに原因にたどり着けたのでしょうか?
今回「NoClassDefFoundError: ObjectMapperの型が解決できません。」と怒られた訳なんですが、ObjectMapper自体はちゃんとロードされていました。
知らなかったんですが、NoClassDefFoundErrorは、そのclassファイルが存在するときも発生する場合があって、そのclassから参照している依存関係が存在しない場合も同様の事象が発生します。
厄介なのが、ビルド時に気付けず実行するまで気づけない場合があることです。
凡ミスで本番障害起こして怒られた人もいっぱいいそうだ…。
私がこの問題で大きく躓いた理由はNoClassDefFoundErrorへの知識不足もありますが、一番は「ObjectMapper.classが本当にロードされているのか」をちゃんと確認せずに原因を探ってたのが悪いと思います。
物事を考えるときは順序だてて1つ1つ変数を取り除いていくのが基本中の基本なのに…。この辺が文系たる所以……。知らんけど
幸いデバッグできる環境だったので、以下の一文を式タブに入力して、ObjectMapper.classがクラスローダに存在するかを最優先で行うべきでした。
this.getClass().getClassLoader().getResource("com/fasterxml/jackson/databind/ObjectMapper.class");
こうやって人は成長していくんだな…。知らんけど