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
.
的实例
具有非 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
.