- PR -

メソッドの入れ替え

投稿者投稿内容
progman
大ベテラン
会議室デビュー日: 2005/06/08
投稿数: 227
投稿日時: 2007-08-20 15:00
レスありがとうございます。
なんとレスつけようかと考えて遅くなってしまいました。
結論をいうと、変更は見送り状態です。

かつのりさんのコーディングでいうと

コード:
public void test(){
    Bean1 bean = class.forName("Bean1") { // ここが、、、
        public String getStr(){
            return super.getStr().toLowerCase();
        }
    };
    bean.setStr("aaa");
    bean.getStr();
}


って書けたらうれしんですが、エラーとなりますね。

プレミアム
会議室デビュー日: 2007/08/15
投稿数: 9
投稿日時: 2007-08-23 15:36
見送り状態とのことですが、調べてみました。
引用:

かつのりさんの書き込み (2007-08-10 10:55) より:
java.lang.instrument.Instrumentation+ASM/Javassist/BCEL...
辺りの組み合わせでできそうな気がしますが、
ビジネスロジックのためにバイトコード操作は、
かえって保守性が悪くなると思います。



上記かつのりさんの意見には賛成ですが、興味があったので、
Javassist説明ページ
http://www.csg.is.titech.ac.jp/~chiba/notes/javapress03/index.html
を参考に実装を検討してみました。
コード:
package test2;
import javassist.*;

public class TestJavassist {
    public static void main(String[] args) throws Exception{
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("test2.Bean1");
        CtMethod m = cc.getDeclaredMethod("getStr1");
        m.insertBefore("return m;");
        cc.writeFile("bin"); //クラスファイルのあるフォルダを指定する
        
        Bean1 bean = new Bean1();
        String ret = bean.run("aBcDe");
        System.out.println(ret);
    }
}


のような感じで、メソッドの振る舞いを強引に変更して、クラスファイル(.classのファイル)を上書きしてくれる様子です。
(※クラスファイルを上書きしない「CtClass#toClass」というメソッドもあるようですが、ここではうまく動きませんでした。)

以下、疑問点・所感など
・もとのクラスファイルへの戻し方はどうするんだろう?もう一回コンパイル?
・ソースファイル(.java)とクラスファイル(.class)の整合性がとれない状態が発生する。
・コード内容は特殊でわかりにくくになると思う→保守性低下と思います。
・(自分が)クラスローダーの走り方・原理等をほぼ理解していないので、使うのはなんとなく不安がある。

てな感じと思います。研究の余地があると思ってます。

非常に有用な面白いツールとは思います。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-08-23 23:12
Javassistなどのバイトコード関連のツールを使う場合、
・生成したバイトコードはクラスファイルに書き込まない
・変更対象のクラスをロードする前に書き換える
・変更対象のクラスがロードされてしまう場合、そのクラスを継承したクラスを生成する
という感じになります。

JDK5のInstrumentationを利用する場合、クラスのローディングをフックできるので、
ロード前のバイトコードを拡張して、変更する事が出来ますが、
JDK1.4や通常の起動を行う場合は、独自のクラスローダを作成するか、
継承クラスの生成が必須となります。

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