- PR -

java.lang.NoClassDefFoundErrorの解決方法について

投稿者投稿内容
未記入
会議室デビュー日: 2005/08/28
投稿数: 6
投稿日時: 2007-07-26 11:56
taku様、mio様ご回答ありがとうございます。

現在、WindowsOSの環境変数CLASSPATHには何も設定していません。
eclipseのビルドパスにはSeasar2が指定するjar置き場と
tomcatのcommon/lib配下のみです。

common/libに問題のjarを置きましたが、以前未解決のままです。

現状はこんな感じです。
○スタンドアロンのJava起動・・・・問題なく動作可能
○単純なサーブレットからの起動(Seasarを使用しない)・・・・問題なく動作可能
×Seasarを使用したサーブレットからの起動・・・・NoClassDefFoundError発生。

また、問題のjarファイルからエラーとなるクラスが格納されているパッケージを
細かく分けて、jarファイルを作り直し、Tomcatのcommon/lib配下に置いたら、
ClassCastExceptionにエラー内容が変わりました。
エラー発生のロジックを通り、後続の処理に移りましたが、
これで問題解決したのかどうか不明です。
以前、対象のjarの中の別のクラスがキャストできていないという感じだからです。

↓こんな対応をしました。
●service.jar(元のjar)
aaa1/bbb1/ccc1/Ddd
aaa1/bbb2/Eee
aaa2/bbb3/Fff
aaa2/bbb3/Ggg

3つにjarファイルを分割
●aaa1-bbb1.jar
 aaa1/bbb1/ccc1/Ddd

●aaa1-bbb2.jar
 aaa1/bbb2/Eee

●aaa2.jar
 aaa2/bbb3/Fff
 aaa2/bbb3/Ggg

DddクラスのNoClassDefFoundErrorエラーが発生しなくなり、
今度はFffクラスがClassCastException例外が発生。


何か気づいたことがあればご指摘ください。
以上、よろしくお願いします。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-26 12:37
引用:

未記入さんの書き込み (2007-07-26 11:56) より:
common/libに問題のjarを置きましたが、以前未解決のままです。

現状はこんな感じです。
○スタンドアロンのJava起動・・・・問題なく動作可能
○単純なサーブレットからの起動(Seasarを使用しない)・・・・問題なく動作可能
×Seasarを使用したサーブレットからの起動・・・・NoClassDefFoundError発生。



本当にcommon/libに置くべきjarなのか考慮していますか?
極力Tomcat/全Webアプリの双方が必要とするものに限定すべきです。

#Tomcat内のみならserver/lib、全Webアプリ共有ならshared/lib
#特に共有させる必要がないのであればwar/WEB-INF/lib

common/libに配置したjarが、war/WEB-INF/{lib,classes}のクラスに
依存しているとNoClassDefFoundError/ClassNotFoundExceptionになります。

直接依存していなくても、リフレクションからロードする場合に、
Thread#getContextClassLoader()を指定せずにClass#forName()すると
自分自身をロードしたクラスローダが使われるために失敗します。

この問題がSeasarにあるとは思いにくいのですが、
「問題のjarはシェアウェア製品の為」はかなり怪しいと思います。

[追記]
ClassCastExceptionが出ているということは、
同一クラスの複数回ロードが原因である可能性もあります。

common/libとwar/WEB-INF/libに同じ名前のクラスがありませんか?
自分で知らなくても、依存しているjarに別のプロダクトのクラスが
同梱されている場合もあります(commons-loggingなどでありがち)。

Webコンテナのクラス解決のポリシーは「子→親」と規定されているので、
普通のクラスローダならば親側のクラスが使われて問題が起こらないのに、
Webコンテナ上では問題が起こるというケースが簡単に作れてしまいます。
[/追記]

[ メッセージ編集済み 編集者: あしゅ 編集日時 2007-07-26 12:49 ]
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2007-07-26 13:40
うーん…。
Eclipseで設定しているビルドパスは、(名前のとおり)ビルド時の参照パスであって、実行時には関係がなくなります(そもそもEclipse自体が実行と関係ない)。
実行時には実行時に参照されるパスがあります。
そこに配置されていなければだめです。

…ということは、理解されているでしょうか。
小僧
ぬし
会議室デビュー日: 2002/08/14
投稿数: 526
投稿日時: 2007-07-26 14:19
引用:

○スタンドアロンのJava起動・・・・問題なく動作可能
○単純なサーブレットからの起動(Seasarを使用しない)・・・・問題なく動作可能
×Seasarを使用したサーブレットからの起動・・・・NoClassDefFoundError発生。



んっ?diconファイルの設定方法が間違えているのではないかと。
クラス名は合っているけどパッケージ名が間違っているとか。

[ メッセージ編集済み 編集者: 小僧 編集日時 2007-07-26 14:19 ]

[ メッセージ編集済み 編集者: 小僧 編集日時 2007-07-26 17:38 ]
未記入
会議室デビュー日: 2005/08/28
投稿数: 6
投稿日時: 2007-07-26 16:32
あしゅ様、mio様、小僧様ご回答ありがとうございます。

あしゅ様
>common/libに置くべきjarなのか考慮していますか?
すいません、Tomcatのjar置き場はcommon/libしかないと
誤認していました。必要としているjarは
コンテナ上で起動するたった一つのサーブレットアプリ
が必要としているのみです。tomcat、seasarの機能では
必要としないものです。

>同梱されている場合もあります(commons-loggingなどでありがち)。
製品のjarの中にありました。。使っています。。
Webサービス機能を提供しているものですので、
commons-logging、axis、activation、mailapi
などが同梱されていまして、他の3つはtomcatかseasarが
使用していたのではずしましたが、commons-loggingを見落としていました。
確認不足でした。

もう少しがんばってみます。
common/libには一切置かず、既に同じパッケージが存在する場合は、
jarでなるべく個別に作成して、重複しないようにしてみます。
・tomcat+seasar
・問題の製品API
の2つがかぶらないようにですね。


mio様
>実行時には実行時に参照されるパスがあります。
たしかにその通りですね。
ただ、eclipseのビルドパスの優先順位を変更した後の
コンパイル、実行で、エラー内容が変わったため、
コンパイルの設定に問題があるのかもしれないと認識しています。


小僧様
>diconファイルの設定方法が間違えているのではないかと。
説明不足ですみません。
問題のjarおよびjarファイル内のクラスはSeasarのAPIではなく、
またSeasarの機能であるコンテナクラスから呼び出されるクラスでもありません。
そのため、dicon定義の問題ではないのではと認識しています。

皆様、貴重なご意見ありがとうございます。

以上、よろしくお願いします。
未記入
会議室デビュー日: 2005/08/28
投稿数: 6
投稿日時: 2007-07-26 18:09
皆様、ありがとうございました。

>common/libには一切置かず、既に同じパッケージが存在する場合は、
>jarでなるべく個別に作成して、重複しないようにしてみます。
>・tomcat+seasar
>・問題の製品API
>の2つがかぶらないようにですね。
かなり細かくjarファイルに小分けして一つずつ動作を確かめてみたのですが、
最終的にはやはり同じクラスキャスト変換エラーが発生してしまいました。
きっと製品APIが独自のクラスローダを呼び出している事が原因なのでしょうね。
そのクラスは製品のコアとなるクラスでtomcat、seasar共に存在しないクラスです。
また、seasarを実装していないサーブレットでは、上記の対応なしで、
呼び出しが可能である為、これ以上の不安要素が後から出てくる事を懸念し、
単純なサーブレットまたはスタンドアロンのJava起動から呼び出す方向で
対応しようと思います。
大変残念なのですが、皆様のアドバイス、技術情報の提供を今後の開発に役立てたいと思います。

ありがとうございました。

スキルアップ/キャリアアップ(JOB@IT)