12

मैं एक POJO कि कुछ करने के लिए एक सेवा का उपयोग करता है अधिलेखित करने के लिए ग्रूवी MetaClass का उपयोग करना:तरीके

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); 
    } 
} 

और मैं एक ग्रूवी परीक्षण का मामला है:

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 काम करता है जैसा कि अपेक्षित था: पीओजेओ IService के गतिशील कार्यान्वयन के साथ बनाया गया है। जब callX का आह्वान किया जाता है, तो यह बस "बहुत गड़बड़" देता है। इस तरह, सेवा का मज़ाक उड़ाया जाता है।

हालांकि मुझे समझ नहीं आता क्यों दूसरी विधि, testMetaClass अपेक्षा के अनुरूप काम नहीं कर रहा है लेकिन इसके बजाय एक NullPointerException जब सेवा वस्तु पर callX आह्वान करने के लिए कोशिश कर फेंकता है। मैंने सोचा कि मैं इस लाइन के साथ doCallService विधि ओवरराइट किया था:

pojo.metaClass.doCallService = { String s -> 

क्या मैं गलत कर रहा हूँ?

धन्यवाद!

उत्तर

16

आपका वाक्यविन्यास एक छोटा सा बंद है। समस्या यह है कि pojo जावा ऑब्जेक्ट है और इसमें मेटा क्लास नहीं है।PlainOldJavaObject के doCallService का उपयोग कर ExpandoMetaClass के लिए कॉल अवरोधन करने के लिए:

बस की जगह:

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

:

PlainOldJavaObject.metaClass.doCallService = { String s -> 
     "no service" 
    } 
+3

यहां ध्यान रखने योग्य एक बात यह है कि जब आप कक्षा के मेटा क्लास में हेरफेर करते हैं, तो उस बिंदु से आगे की प्रत्येक घटना का उपयोग किया जाएगा। यह उसी सत्र में चलने वाले अन्य परीक्षणों पर एक बड़ा प्रभाव डाल सकता है। जब आप किसी वर्ग के उदाहरण में हेरफेर करते हैं, तो केवल वह उदाहरण प्रभावित होता है। –

1

जो आपने ठीक दिखता है। मैंने ग्रोवी कंसोल वेबपैप पर थोड़ा संशोधित संस्करण चलाया और यह बिना किसी समस्या के भाग गया। 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") 

ग्रोवी का आप किस संस्करण का उपयोग कर रहे हैं। मेटाक्लास कार्यान्वयन में ग्रोवी में यह बहुत अच्छी तरह से एक बग हो सकता है। ग्रोवी भाषा बहुत तेज़ी से चलता है और मेटाक्लास कार्यान्वयन संस्करण से संस्करण में बदल जाता है।

संपादित करें - टिप्पणी से फीडबैक:

ग्रूवी सांत्वना webapp के संस्करण 1.7-rc-1 है। तो ऐसा लगता है कि संस्करण काम कर सकता है जैसा आप चाहते हैं। वे वर्तमान में आरसी 2 में हैं इसलिए मुझे उम्मीद है कि इसे जल्द ही रिहा कर दिया जाएगा। सुनिश्चित नहीं है कि आप जो देख रहे हैं वह एक बग है या 1.6.x संस्करण में यह कैसे काम करता है इसमें एक अंतर है।

+0

हाय क्रिस, मैं ग्रूवी संस्करण चलाएँ: 1.6.5 JVM: 1.6.0_13 – raoulsson

+0

संस्करण इसके साथ कुछ लेना देना नहीं है। समस्या यह है कि doCallService (x) जावा कोड है, न कि ग्रोवी कोड, इसलिए यह मेटा क्लास नहीं है। – noah

15

यदि आपका POJO वास्तव में जावा क्लास है, और ग्रोवी क्लास नहीं है, तो यह आपकी समस्या है। जावा क्लासेस मेटा क्लास के माध्यम से तरीकों का आह्वान नहीं करते हैं। उदाहरण के लिए, ग्रूवी में:

pojo.publicMethod('arg') 

इस जावा के बराबर है:

invokeMethod metaClass के माध्यम से कॉल भेजता है। लेकिन यह विधि:

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

जावा विधि है। यह doCallService पर कॉल करने के लिए invokeMethod का उपयोग नहीं करता है। अपना कोड काम करने के लिए, PlainOldJavaObject को ग्रोवी क्लास होने की आवश्यकता है ताकि सभी कॉल मेटा क्लास के माध्यम से जा सकें। सामान्य जावा कोड मेटा क्लासेस का उपयोग नहीं करता है।

संक्षेप में: यहां तक ​​कि ग्रोवी जावा विधि कॉल को ओवरराइड नहीं कर सकता है, यह केवल ग्रोवी से कॉल ओवरराइड कर सकता है या अन्यथा invokeMethod के माध्यम से प्रेषित हो सकता है।

+0

ग्रोवी कोड और जावा कोड के बीच आप सही ढंग से अंतर कैसे करते हैं? PlainOldJavaObject के बजाय आप PlainOldGroovyObject कैसे बनायेंगे? – Tomato

+4

यदि यह एक .groovy फ़ाइल में है, तो यह एक ग्रोवी क्लास है। – noah

+0

इसे मिला। स्पष्टीकरण के लिए धन्यवाद :) – Tomato

संबंधित मुद्दे