久しぶりにブログ書きます。
最近ちょっとずつ、本業務の方が忙しくなってきたので、
疎かになってしまっておりました。。。
○ClassNotFoundExceptionのワナ
JavaでClassNotFoundExceptionが発生するとき、
あなたならまず何を疑いますか?
1.パスが通っていない
2.クラス名のスペルミス
3.そもそもクラスファイル(.class)が存在していない
大体、経験を積んできた皆さんであれば、こういった予想に辿り着くでしょう。
それで、まぁ僕も例のごとくこの可能性を探ったんですが、
一向に問題を解決出来ないという局面に立たされてしまいました。
僕のケースを説明します。
---------前提条件---------
APサーバー
・JBossEAP6
デプロイしてるもの
・アプリ(Earファイル)
・リソースアダプター(rarファイル)
---------------------------
1.パスが通っていない
まず、これを考えますよね。必要なjarファイル、またはclassファイルは存在しているのか。
でも、デプロイされたrarからはそのクラスが呼び出せている。
それなのにEarからは呼び出せていない。。。怪しい。
2.クラス名のスペルミス
これはめちゃくちゃ確認しましたが、大丈夫でした笑
3.そもそもクラスファイル(.class)が存在していない
rarファイル内のjar内に該当クラスがあることは確認しています。
1のクラスパスの怪しさはあるものの、JBossからは該当クラスは見ることが出来ています。
アプリケーション側(Ear側)から見ることが出来ない。
その場しのぎで、必要なjarをEar/libの直下に入れてみることにしました。
その結果、ClassNotFoundは解消されましたが・・・・・・・・
○ClassCastException発生
クラスが見えるようになってひと安心。と思いきや、キャストエラーが発生してしまいました。
継承関係から言って、スーパークラスへのキャストなので、例外が発生するはず無いのに!あれ???
はじめは別のパッケージの同名クラスでも見てしまってるのかと思いましたが、
違いました。
○原因はクラスローダー
型や、継承関係が不正でなくてもクラスローダーが原因でキャスト例外が発生してしまうことがあるのです。
散々悩んでいましたが、盲点でした。
同じクラスを別のクラスローダーで重複して読み込むとClassCastExceptionが発生することがあります。
僕のケースでは、アプリ(Ear)側のクラスローダーで読み込んだクラスからリソースアダプター(rar)側のクラスローダーで読み込んだクラスへキャストしようとしたため、
キャストが出来なかったのです。
実際にこの状態で以下のコードを埋め込んでみたところ、別のクラスローダーからクラスを参照しているため、
正しくインスタンスを認識できていませんでした。
//リソースアダプターからJNDIバインドされたクラスをルックアップ Context ctx = new InitialContext(env); Object ref = ctx.lookup("java:/jboss/JndiBindedClass"); System.out.println(ref.getClass().getClassLoader());//←EARのクラスローダー System.out.println(JndiBindedClass.class.getClassLoader());//←rarのクラスローダー //実装インターフェースの取得 String[] ifs = ref.getClass().getInterfaces(); for(int i=0; i < ifs.length; i++){ System.out.println("実装インターフェース" + ifs[i]); }//←実装しているインターフェースは同じでした if (ref instanceof JndiBindedClass){ System.out.println("JndiBindedClassのインスタンス"); }//←falseになってしまう if (JndiBindedSuperClass.class.isAssignableFrom(ref.getClass()){ System.out.pritnln("JndiBindedSuperClassを継承している。"); }//←falseになってしまう (JndiBindedSuperClass) ref.DoSuperMethod();//←ここでキャストエラー
結局、振り出しに戻り、クラスパスを整理したところ、同じクラスローダーを参照するようになり、 ClassNotFoundとClassCastの問題は解決しましたとさ・・・・。
この問題は、JBossEAP6は階層型クラスローダーではなくモジュール型のクラスローダーであることが要因として大きいのかもな。
思わぬところでキャスト例外が発生したとき、このエントリが皆さんの参考になれば嬉しいです。
0 件のコメント:
コメントを投稿