2011年10月8日土曜日

リフレクションでNoSuchMethodErrorが起きてる

今回も落ちなしです!

研究でEclipseプラグインを拡張するプラグインを作っていたのだが、思わぬエラーに時間を取られてしまった。

java.lang.NoSuchMethodError
呼び出すべきメソッドが実装されていない場合に起こるエラーです。通常はメインメソッドを書かずに実行してしまった、開発環境と実行環境のライブラリの同期がとれていないなど、コンパイルエラーで出て欲しいエラーが実行時に出てしまうエラーです。

自分の場合、上記の条件は当てはまらず、しかもそのメソッドは自分が実装したクラスのコンストラクタでした。

コンストラクタを実行しようとするとソースファイルには記述されているにもかかわらず、NoSuchMethodErrorが発生してしまい、プログラムが動きません。

こういう場合、まずプロジェクトのクリーンを行うべきです。binフォルダ内のクラスファイルがうまく更新されていない場合があるので。

しかしクリーンを実行しても解決せず、故意的にbinフォルダを削除してからビルドし直しても動かない始末。拉致があかないので、クラスローダに登録されているクラスの情報を見てみることにしました。
Class<EditFWModelActorWP> clz = EditFWModelActorWP.class;
for(Constructor<?> c : clz.getConstructors()){
System.out.println(c.toGenericString());
}
この他にもClass型オブジェクトには様々なメソッドがあるので、チェックするときに便利です。

結果は、昔のクラスの内容が登録されていました。なぜ!?クラスファイルもソースも消してあるから、昔のクラスの情報なんて得られるわけないのに。

じゃあ対象クラスの名前を変更してやろうと思って変更すると、なんと残念な引数のままクラスもコンストラクタもリファクタリングされた!←おそらく、クラス内部ではコンストラクター名ではなく、initとかで認識しているんだろう。

どうやらどこかにクラスファイルが残っていて、それを誤って読み込んでるという状況ではないらしい。

そうなると、何を疑えばいいのかわからなくなる。

いろいろ試してみた結果、不具合が起きているのはWindowBuilderを利用してソースを自動生成したクラスだけだった。自分はそのクラスにコンストラクタを追加した。
その後そのクラスをWindowBuilderを立ち上げると、”勝手にコンストラクタを加えると俺達わかんなくなっちゃいます”ってメッセージが表示された。

やっと原因を見つけた!と思い言われたとおり利用するコンストラクタにアノテーションを追加するも、何の変化もなし。でもEclipseプラグイン開発のデバッグ内だったためにクラスのコンストラクタにリフレクションでアクセスしたことと、WindowBuilderの仕様に関係があると考えるのが一番だと思う。

結局、エラーの原因はわかりませんでしたが、
新たに別名のクラス(今回はTmp)を作る
ソース単位で中身をコピー
手動でコンストラクタ名をTmpに
依存する場所もすべて手動でTmpに
これでうまく動いた。でも名前戻したらエラーが出る笑
違う名前だと問題ないんだよね。なんだろ?

一応そのエラーが出た名前でファイルシステムを検索したら、
.java, .classの他に、2つ記述されているファイルがみつかった。
workspace\.metadata\.plugins\org.eclipse.jdt.ui\QualifiedTypeNameHistory.xml
workspace\.metadata\.plugins\org.eclipse.ui.workbench\workbench.xml
これらは何を意味するのだろうか?なんとなく後者は問題ない気がする。

もしかしたら上記2つの状況と、Eclipseの仕様がうまい具合に合わさって変なエラーになっているのかもしれない。そうだとしたらリファクタリングを使って名前を変更すると解決しない状況もつじつまが合う。

何だったのやら…時間ないのに(-_-;)

誰か同じような現象を経験していて、原因がわかった人は教えてください。

1 件のコメント:

  1. Objectを参照できませんってなった場合は、
    そのクイックフィックスで表示されるビルドパスの構成で、
    JREをチェックすれば戻るということがわかりました。

    返信削除