16

サービスを使用して何かを行う POJO があります。

public class PlainOldJavaObject {

    private IService service;

    public String publicMethod(String x) {
        return doCallService(x);
    }

    public String doCallService(String x) {
        if(service == null) {
            throw new RuntimeException("Service must not be null");
        }
        return service.callX(x);
    }

    public interface IService {
        String callX(Object o);
    }
}

そして、Groovy テスト ケースがあります。

class GTest extends GroovyTestCase {

    def testInjectedMockIFace() {
        def pojo = new PlainOldJavaObject( service: { callX: "very groovy" } as IService )
        assert "very groovy" == pojo.publicMethod("arg")
    }

    def testMetaClass() {
        def pojo = new PlainOldJavaObject()
        pojo.metaClass.doCallService = { String s ->
            "no service"
        }
        assert "no service" == pojo.publicMethod("arg")
    }
}

最初のテスト メソッドは、testInjectedMockIFace期待どおりに機能します。POJO は、の動的実装で作成されIServiceます。がcallX呼び出されると、単純に「非常にグルーヴィー」を返します。このようにして、サービスはモックアウトされます。

testMetaClassただし、2 番目のメソッドが期待どおりに機能せず、代わりにcallXサービス オブジェクトで呼び出そうとすると NullPointerException がスローされる理由がわかりません。メソッドを次の行で上書きしたと思いましたdoCallService

pojo.metaClass.doCallService = { String s ->

私は何を間違っていますか?

ありがとう!

4

3 に答える 3

20

あなたの構文は少しずれています。問題は、pojo が Java オブジェクトであり、metaClass がないことです。ExpandoMetaClass を使用して PlainOldJavaObject の doCallService への呼び出しをインターセプトするには:

置き換えるだけです:

    pojo.metaClass.doCallService = { String s ->
        "no service"
    }

と:

    PlainOldJavaObject.metaClass.doCallService = { String s ->
        "no service"
    }
于 2010-03-08T20:12:52.113 に答える
18

POJO が本当に Java クラスであり、Groovy クラスではない場合、それが問題です。Java クラスは、metaClass を介してメソッドを呼び出しません。たとえば、Groovy では次のようになります。

pojo.publicMethod('arg')

は、次の Java と同等です。

pojo.getMetaClass().invokeMethod('publicMethod','arg');

invokeMethodmetaClass を介して呼び出しを送信します。しかし、この方法:

public String publicMethod(String x) {
    return doCallService(x);
}

Java メソッドです。invokeMethodを呼び出すのには使用しませんdoCallService。コードを機能PlainOldJavaObjectさせるには、すべての呼び出しが metaClass を通過するように、Groovy クラスである必要があります。通常の Java コードはメタクラスを使用しません。

要するに、Groovy でさえ Java メソッド呼び出しをオーバーライドすることはできませ

于 2009-12-28T20:59:54.680 に答える
1

あなたが持っているものはうまく見えます。groovy console webappで少し変更したバージョンを実行しましたが、問題なく実行されました。http://groovyconsole.appspot.com/でこのコードを使用して自分の目で確かめてください。

public interface IService {
    String callX(Object o);
}

public class PlainOldJavaObject {

    private IService service;

    public String publicMethod(String x) {
        return doCallService(x);
    }

    public String doCallService(String x) {
        if(service == null) {
            throw new RuntimeException("Service must not be null");
        }
        return service.callX(x);
    }
}

def pojo = new PlainOldJavaObject()
pojo.metaClass.doCallService = { String s ->
    "no service"
}
println pojo.publicMethod("arg")

使用しているGroovyのバージョン。これは、メタクラス実装のGroovyのバグである可能性が非常に高いです。グルーヴィーな言語は非常に速く動き、メタクラスの実装はバージョンごとに変わります。

編集-コメントからのフィードバック:

groovyconsolewebappのバージョンは1.7-rc-1です。そのため、そのバージョンは希望どおりに機能する可能性があります。現在RC2になっているので、まもなくリリースされると思います。表示されているのがバグなのか、1.6.xバージョンでの動作の違いなのかわからない。

于 2009-12-18T12:21:53.757 に答える