ग्रूवी में एक विधि का उपयोग कर metaClass टूट गया है एक अंतरफलक में परिभाषित की जगह। इस मामले में, exec
विधि Project
कक्षा में परिभाषित की गई है, जो एक इंटरफ़ेस है। GROOVY-3493 से (सूचना 2009 में मूल रूप से):
"Cannot override methods via metaclass that are part of an interface implementation"
कारगर युक्तियाँ
invokeMethod
अवरोध सभी तरीकों और काम कर सकते हैं। यह अधिक है लेकिन यह काम करता है। जब विधि का नाम exec
से मेल खाता है, तो यह कॉल को mySpecialInstance
ऑब्जेक्ट में बदल देता है। अन्यथा यह प्रतिनिधि, अर्थात् मौजूदा तरीकों से गुजरता है। इस पर इनपुट के लिए invokeMethod delegation और Logging All Methods पर धन्यवाद।
// This intercepts all methods, stubbing out exec and passing through all other invokes
this.project.metaClass.invokeMethod = { String name, args ->
if (name == 'exec') {
// Call special instance to track verifications
mySpecialInstance.exec((Closure) args.first())
} else {
// This calls the delegate without causing infinite recursion
MetaMethod metaMethod = delegate.class.metaClass.getMetaMethod(name, args)
return metaMethod?.invoke(delegate, args)
}
}
यह सिवाय आप के बारे में "तर्कों की गलत संख्या" या "अशक्त वस्तु पर विधि xxxxx आह्वान नहीं कर सकते" अपवाद देख सकते हैं कि अच्छी तरह से काम करता है। समस्या यह है कि उपरोक्त कोड विधि तर्कों के समन्वय को संभाल नहीं करता है। project.files(Object... paths)
के लिए, invokeMethod के लिए तर्क [['path1', 'path2']]
के रूप में होना चाहिए। लेकिन, कुछ मामलों में files(null)
या files()
पर कॉल किया गया है, इसलिए invokeMethod के लिए तर्क [null]
और []
क्रमशः [[]]
की अपेक्षा करते हैं। उपरोक्त त्रुटियों का निर्माण।
निम्न कोड केवल files
विधि के लिए इस को हल करती है, लेकिन है कि मेरी इकाई परीक्षण के लिए पर्याप्त था। मैं अभी भी एक विधि को बदलने या आदर्श रूप से एक विधि को बदलने का एक बेहतर तरीका खोजना चाहता हूं।
// As above but handle coercing of the files parameter types
this.project.metaClass.invokeMethod = { String name, args ->
if (name == 'exec') {
// Call special instance to track verifications
mySpecialInstance.exec((Closure) args.first())
} else {
// This calls the delegate without causing infinite recursion
// https://stackoverflow.com/a/10126006/1509221
MetaMethod metaMethod = delegate.class.metaClass.getMetaMethod(name, args)
logInvokeMethod(name, args, metaMethod)
// Special case 'files' method which can throw exceptions
if (name == 'files') {
// Coerce the arguments to match the signature of Project.files(Object... paths)
// TODO: is there a way to do this automatically, e.g. coerceArgumentsToClasses?
assert 0 == args.size() || 1 == args.size()
if (args.size() == 0 || // files()
args.first() == null) { // files(null)
return metaMethod?.invoke(delegate, [[] as Object[]] as Object[])
} else {
// files(ArrayList) possibly, so cast ArrayList to Object[]
return metaMethod?.invoke(delegate, [(Object[]) args.first()] as Object[])
}
} else {
// Normal pass through
return metaMethod?.invoke(delegate, args)
}
}
}
मुझे 100% यकीन नहीं है कि यह काम करेगा, लेकिन आप मेरे ब्लॉग पर ओवरराइडिंग विधियों के बारे में एक और पोस्ट में तकनीक का उपयोग करने में सक्षम हो सकते हैं लेकिन अभी भी मूल कार्यान्वयन का उपयोग कर सकते हैं: http://naleid.com/ब्लॉग/200 9/06/01/ग्रोवी-मेटाक्लास-ओवरराइडिंग-ए-विधि-जबकि-पुराने-कार्यान्वयन-पुराने-कार्यान्वयन यह इंटरफ़ेस समस्या द्वारा अवरुद्ध हो सकता है जिसे आपने पहचाना है ... यदि ऐसा है, तो समाधान जो आपने मेरे लिए एक अच्छा दिखता है। –
धन्यवाद टेड, इंटरफ़ेस को काम करने से रोकने के साथ यह वही समस्या है। मुझे कॉरर्सिंग प्रकारों पर आपके विचारों में दिलचस्पी है। सरल कोड 'project.files (ऑब्जेक्ट ... पथ) 'के लिए' फ़ाइलें (शून्य) 'और' फ़ाइलें()' के लिए विफल रहता है। क्या एक सामान्य तरीके से एक varargs पैरामीटर के लिए प्रकारों को मजबूत करने का कोई बेहतर तरीका है? सुधार के साथ मेरी पोस्ट को संपादित करने के लिए स्वतंत्र महसूस करें। – brunobowden