2011-05-06 27 views
7

クラスがインスタンス化されたときにコンストラクタにコードを追加できる方法はありますか?私はGroovyクラスを持っていますが(私はこの特定のソースを変更することはできません)、私のコードがコンストラクタの一部として実行されるように(おそらくメタクラスを介して)コードを注入する方法があることを期待していましたデフォルトのコンストラクタは1つだけです)。Groovyがコンストラクタにコードを追加する

おかげで、 ジェフ

+2

これは決して自分自身ではありませんでしたが、これはhttp://groovy.codehaus.org/ExpandoMetaClass+-+Constructors –

+0

優れたリンク –

答えて

8

あなたコンストラクタをオーバーライドすることができますが、それはあなたがデフォルトコンストラクタをオーバーライドしている場合は特に、少しトリッキーです。クラスのmetaClass.constructorにクロージャを割り当てる必要があり、クロージャは新しいインスタンスを返す必要があります。トリッキーな部分は、オーバーライドしたコンストラクタを呼び出すと、再帰的なループに入り、スタックのオーバーフローが発生することです。別のコンストラクタなど、クラスのインスタンスを取得する別の方法が必要です。

テストでは、この制限を回避することができます。通常は、最初にオブジェクトをインスタンス化してから、既存のインスタンスを返すようにコンストラクタをオーバーライドするだけで十分です。例:

class MyObject { 
    String something 
    MyObject() { something = "initialized" } 
} 

testInstance = new MyObject() 
testInstance.something = "overriden" 
MyObject.metaClass.constructor = { -> testInstance } 

aNewObject = new MyObject() 
assert aNewObject.is(testInstance) 
assert aNewObject.something == "overriden" 
+0

私は達成するためには2つのコンストラクタを使用できるはずです。ありがとう。 –

2

新しいコンストラクタを追加したり、古いコンストラクタを置き換えることは可能です。あなたは、元のコンストラクタが必要な場合は、そのためにリフレクションを使用することができます:あなたがあなたのコンストラクタにパラメータを持っている場合は、これを変更する必要が

MyObject.metaClass.constructor = { -> // for the no-arg ctor 
    // use reflection to get the original constructor 
    def constructor = MyObject.class.getConstructor() 
    // create the new instance 
    def instance = constructor.newInstance() 
    // ... do some further stuff with the instance ... 
    println "Created ${instance}" 
    instance 
} 

注、例えば:

// Note that the closure contains the signature of the constructor 
MyObject.metaClass.constructor = { int year, String reason -> 
    def constructor = MyObject.class.getConstructor(Integer.TYPE, String.class) 
    def instance = constructor.newInstance(
    2014, "Boy, am I really answering a question three years old?") 
    // ... do some further stuff with the instance ... 
    println "Created ${instance}" 
    instance 
} 

PS:ときことに注意してくださいまだ存在しないコンストラクタを追加する場合は、MyObject.metaClass.constructor << { /* as above */ }の代わりに<<演算子を使用します。

1

標準のJavaリフレクションを使用して元のコンストラクタを保存することで提案されたソリューションの制限を回避できます。たとえば、これは私がスポックのテストでクラス(基本噴射)を初期化何をすべきかです:

def setupSpec() { 
    MockPlexusContainer mockPlexusContainer = new MockPlexusContainer() 
    def oldConstructor = MY_CLASS.constructors[0] 

    MY_CLASS.metaClass.constructor = { -> 
     def mojo = oldConstructor.newInstance() 
     mockPlexusContainer.initializeContext(mojo) 
     return mojo 
    } 
} 

この一度だけ呼び出されるが、eveytime誰かが私が掃除値を回避し、糸を確実に別のインスタンスを取得するコンストラクタを呼び出し安全性。

関連する問題