Groovy の メタクラス でメソッドの処理を差し替えても Java から呼び出したら替ってないのか…
タイトルの通り。あくまでも メタクラス っていう Groovy 側が持っている物に登録しているから、それを利用せずに呼び出す Java からでは変更されないのかな?
Groovy イン・アクション の メタプログラミング の章 を読んでみようか。
ちなみに、やりたかった事はこんな感じ*1です。
DAC.java
interface IDAC { Object getByPK(int id); void insert(Object dao); } public class DAC implements IDAC { public Object getByPK(int id) { // どっかのストレージ等から取得する // 今回はとりあえず null を返している return null; } public void insert(Object dao) { // どっかのストレージに登録する // 今回はとりあえず "insert" と出力する System.out.println("insert"); } }Service.java
public class Service { private IDAC dac; public Service() { this.dac = new DAC(); } public void proc() { while (true) { this.dac.insert(new Object()); if (何かしら条件分岐()) { break; } } } private boolean 何かしら条件分岐() { // 何かしらの条件分岐に IDAC.getByPK が必要。 return this.dac.getByPK(1) == null; } }
ってな感じの Java のコードがあったとして、 Service.proc 内で IDAC.insert が何回呼ばれているかを調べるために、Groovy から呼び出して DAC の insert メソッド の実装を差し替えて呼び出されたカウントを取ろうとしました。
DAC.metaClass.insert = { Object dao -> (void) } // 型のメタクラスで insert メソッド を差し替える def s = new Service(); def cnt = 0 s.dac.metaClass.insert = { Object dao -> // 更にインスタンスのメタクラスで insert メソッド を差し替える cnt++ (void) } s.proc() // s.dac.insert(new Object()) Groovy で呼び出した場合は、差し替えた処理が走り、cnt がインクリメントされる assert s.dac.cnt == 1
試してみましたが、差し替えた処理は走らずに、元の処理("insert" と出力する) が走り cnt の値は 0 のままでした。
ちなみに Groovy から s.dac.insert メソッドを呼び出すと、差し替えた処理が走り cnt は増加していきました。
結局上の方法では実現出来ませんでしたが、Service.dac フィールド自体を差し替えると実現出来たので良しとします。
class DACCustom extends DAC { int cnt = 0 // getByPK は変更しない public void insert(Object dao) { cnt++; } } def s = new Service(); s.dac = new DACCustom() s.proc() assert s.dac.cnt == 1