Groovy 的 missingMethod 不会在 Closure 的委托上调用以隐式调用非 Groovy 对象

Groovy's missingMethod is not called on a Closure's Delegate for implicit calls to non-GroovyObjects

具有非 groovy-对象(例如,来自普通 java-库)的委托的闭包永远不会调用添加到该委托的 'methodMissing' 对象使用它的 metaclass,如果调用是 'implicit'(即不在闭包内的 'delegate' 上显式调用它。)

下面的代码对不存在的方法进行了显式和隐式调用;它在 Groovy-class 实例、GString 和非 groovy 对象上这样做。唯一失败的是对非 groovy 对象 (i.c.ArrayList).

的隐式调用

(网上可以看到和运行一样的代码: https://groovyconsole.appspot.com/edit/5200829376102400)

不确定这是错误还是限制 - 对通过 metaClass 定义的 methodMissing 的引用非常少。欢迎任何有见地的评论。

class ClosureDelegate {
    def testMissingMethod(def someObject) {
        someObject.metaClass.methodMissing = { String name, args ->
            println name
        }
        def closure = {
            delegate.anything()
            anything() // this one fails on non-groovyclasses
        }
        closure.delegate = someObject
        closure.resolveStrategy = Closure.DELEGATE_ONLY
        closure()
    }
}

class TestObject {}

println "testing with TestObject"
new ClosureDelegate().testMissingMethod(new TestObject())
println "testing with GString"
new ClosureDelegate().testMissingMethod("${new Date()}")
println "testing with ArrayList"
new ClosureDelegate().testMissingMethod(new ArrayList())
testing with TestObject
anything
anything
testing with GString
anything
anything
testing with ArrayList
anything
Caught: groovy.lang.MissingMethodException: No signature of method: ClosureDelegate$_testMissingMethod_closure2.anything() is applicable for argument types: () values: []
Possible solutions: toString(), toString(), any(), any()

根据 ClosureMetaClass 实施,此行为是预期的。查看该文件中从第 275 行开始的以下部分:

    switch (resolveStrategy) {
        case Closure.TO_SELF:
            break;
        case Closure.DELEGATE_ONLY:
            method = getDelegateMethod(closure, delegate, methodName, argClasses);
            callObject = delegate;
            if (method == null) {
                invokeOnDelegate = delegate != closure && (delegate instanceof GroovyObject);
            }
            break;

来源:src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java#L275-L284

invokeOnDelegate 布尔标志验证委托对象是否扩展 GroovyObject(所有 Groovy classes 的默认父 class。)当你使用 Groovy classes 执行代码,此标志设置为 true 并调用委托对象的 anything 方法。在非Groovy classes的情况下,抛出MethodMissingException

您可以通过在 AbstractCallSite.callCurrent(GroovyObject receiver) 行 160 中设置断点来调试此行为。您将看到在所有情况下都没有在闭包中找到方法 anything,但在前两种情况下invokeOnDelegate 被评估为 true,并执行委托对象上的 invokeMethod。在第三种情况下不会发生,因为 ArrayList 不是 GroovyObject.

的实例