我在Groovy中遇到了一个非常奇怪的行为。当我在脚本中从闭包抛出异常时,所抛出的结束异常是不同的。
下面是代码和细节:
public class TestDelegate {
def method(Closure closure) {
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure.delegate = this;
closure.call();
}
public static void main(String[] args) {
// Make Script from File
File dslFile = new File("src/Script.dsl");
GroovyShell shell = new GroovyShell();
Script dslScript = shell.parse(dslFile);
TestDelegate myDelegate = new TestDelegate();
dslScript.metaClass.methodMissing = {
// will run method(closure)
String name, arguments ->
myDelegate.invokeMethod(name, arguments);
}
dslScript.metaClass.propertyMissing = {
String name ->
println "Will throw error now!"
throw new MyOwnException("errrrror");
}
dslScript.run();
}
}
class MyOwnException extends Exception {
public MyOwnException(String message) {
super(message);
}
}
脚本。dsl:
method {
println a;
}
因此计划是,当我在TestDelegate
中运行main()
方法时,它将运行DSL脚本,该脚本调用method()
方法。没有在脚本中找到它,它将调用methodMissing
,然后从myDelegate
调用method()
,后者依次调用闭包,将委托设置为testDelegate
。到目前为止,一切顺利。然后闭包应该尝试打印"a",它没有定义,因此会触发propertyMissing
,这将会抛出MyOwnException
。
然而,当我运行代码时,我得到以下输出:
Will throw error now!
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: a for class: TestDelegate
现在,它一定到达了catch块,因为它输出了"Will throw error Now !"它一定也把MyOwnException
扔了!但在某个地方,MyOwnException
被转换为MissingPropertyException
,我不知道为什么。有人知道吗?
注:如果我从TestDelegate#method()
中删除closure.setResolveStrategy(Closure.DELEGATE_FIRST)
,代码将按照预期运行并抛出MyOwnException
。但是我的DSL项目真的需要setResolveStrategy(Closure.DELEGATE_FIRST)
。我更愿意知道问题的根本原因,而不是仅仅删除一两行,然后在不了解原因的情况下看到它可以工作。
我认为本质上是这样的:使用委托优先解析策略,Groovy运行时首先尝试访问myDelegate
上的属性a
,这将导致MissingPropertyException
,因为不存在这样的属性。然后尝试propertyMissing
,这导致抛出一个MyOwnException
。最终,运行时放弃并重新抛出遇到的第一个异常(设计决策),该异常恰好是MissingPropertyException
。
使用所有者优先的解析策略,propertyMissing
首先被咨询,因此MyOwnException
最终被重新抛出。
查看下面的堆栈跟踪和源代码应该会提供更多证据。