Groovy结束异常与抛出异常不同



我在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最终被重新抛出。

查看下面的堆栈跟踪和源代码应该会提供更多证据。

最新更新