R42日記スマートフォン用の表示で見るスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。読者です読者をやめる読者になる読者になるR42日記この日記は私的なものであり、所属会社の見解ではありません。到るまで半日要したのだが、Eclipse3.5のJavaコンパイラ(ecj)に致命的なバグがあることを発見した。『非publicな親クラスから引き継いだpublicメンバーを、異なるパッケージにおいて子クラス経由でリフレクションで呼び出すとエラーになる』というもの。コードを見たほうが早いので、下のコードを見るべし。リフレクションで呼び出す。こちらも正常動作する。リフレクションで呼び出す。}}このとき、FooMainの実行結果は以下のとおり。method1method1しかし、BarMainの実行結果はこの通りだ。bar.BarMain.main(BarMain.java:23)何故かIllegalAccessExceptionが発生する。ひとつ上で、実際にコンパイル可能なコードの実行が成功している(当たり前だが)のにもかかわらず。原因考察Java言語仕様的には、非publicクラスから継承したpublicメンバーは、子クラスのpublicメンバーとして扱われる。pc.method1();は何の問題もなくコンパイルが成功する。最初は、通常のメソッド呼び出し"pc.aMethod"()はコンパイルもでき、もちろん正常に動作するのに、リフレクションだと失敗するというのが信じられなかった。自分が何か、致命的な勘違いをしているのではないか、と。試行錯誤の末、javacでコンパイルした場合は正常に動作することを発見し、それが突破口になった。4:return}この通り、違いが明らかだ。ecjのコンパイル結果にはaMethodが存在しない。この問題、かなり昔にSunのメーリングリストでバグレポートが上がっていた模様。SunJDKでは当然ながら修正済みなんだが、ecjでは発生しているということはもしかしてecjとjavacはコードベースが共通なのか?歴史的にはそんなことはないハズなんだが。非publicクラスにはpublicメンバーを宣言しない正直、選択肢4は制約がきつすぎる。選択肢3はうっかりミスが怖い。個人的には選択肢2をオススメするが、選択肢1もアリだろう。商用環境でこんなバグが出たらと思うとゾッとするよ、マジで。『コンパイラが怪しい』なんて疑うことはまずない。そんなこと言っても誰も信じてくれないだろう。僕がそういう報告を受けたなら、まず先に担当者のトラブルシューティング能力の方を疑う。