【问题标题】:Set Delegate for the Groovy Script With BaseScript使用 BaseScript 为 Groovy 脚本设置委托
【发布时间】:2023-03-26 15:37:01
【问题描述】:

我的应用程序中有以下一段运行脚本的代码

    CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
    compilerConfiguration.setScriptBaseClass(DelegatingScript.class.getName());
    GroovyShell shell = new GroovyShell(compilerConfiguration);

    try {
        String scriptText = "";
        try (Scanner scanner = new Scanner(resources[0].getInputStream())){
            scriptText = scanner.useDelimiter("\\A").next();
        }

        DelegatingScript script = (DelegatingScript)shell.parse(scriptText);
        script.setDelegate(this.getDelegate());
        script.run();
    } catch (IOException e) {
        throw new IllegalArgumentException("Cannot read script resource: '" + filename + "': " + e.getLocalizedMessage(), e);
    }

它适用于 Groovy 脚本,直到我开始将一些功能重构到 @BaseScript 类中。所以,例如我有这个 Groovy 类

package com.example.scripts

abstract class MyBaseScriptClass extends Script {
    int getTheMeaningOfLife() { 42 }
}

然后我有脚本

package scripts

import com.example.scripts.MyBaseScriptClass
import groovy.transform.BaseScript

@BaseScript MyBaseScriptClass baseScript

add(context.application, 'test', theMeaningOfLife )

运行失败,报错:

Caused by: java.lang.ClassCastException: scripts.Script1 cannot be cast to groovy.util.DelegatingScript
    at com.metlife.harmony.scripts.groovy.dsl.RunScript.call(RunScript.java:86) ~[classes/:?]

也就是说,如果我在课堂上使用 @BaseScript ,它无法将其转换为 DelegatingScript ?有什么解决办法吗?

【问题讨论】:

  • 只是让 MyBaseScriptClass 扩展 DelegatingScript ? RunScript 看起来像一个自定义代码,需要将脚本转换为 DelegatingScript
  • 不,扩展 DelegatingScript 不起作用。我需要将脚本强制转换为委托以便为其设置委托script.setDelegate(this.getDelegate()); 这是一种传递执行上下文的方法 - 而不是设置绑定需要显式设置变量,我只使用委托机制。
  • 我知道,但是@BaseScript 会覆盖您的 setScriptBaseClass(DelegatingScript)。您的脚本的基类是 MyBaseScriptClass,这不能转换为 DelegatingScript
  • 对,但是MyBaseScriptClass extends DelegatingScript 不起作用,同样的错误。
  • 其实错误是不一样的。 theMeaningOfLife 在我的脚本中返回 null

标签: groovy


【解决方案1】:

为了总结cmets:

@BaseScript 覆盖 setScriptBaseClass(DelegatingScript.class.getName())。 MyBaseScriptClass 没有扩展 DelegatingScript,因此 RunScript 中的转换失败。

要修复此错误,您应该将 MyBaseScript 更改为 extends DelegatingScript。

abstract class MyBaseScriptClass extends DelegatingScript {
    int getTheMeaningOfLife() { 42 }
}

如果你想绕过 DelegatingScript,你应该检查一下 script 是否是 DelegatingScript 的实例?如果是,设置委托,如果不是,什么都不做?

在脚本内部,您可以尝试更改您的委托,但只有在当前委托没有覆盖 baseScript 属性时才会起作用:

baseScript.delegate = baseScript

【讨论】:

  • 这对我来说都没有 100% 的帮助。如果我扩展DelegatingScript,它确实修复了转换错误,但是我在脚本中使用的所有属性(具有@BaseScript anno 的属性)都返回null。查看DelegatingScript 的源代码后,我发现只有属性才会以这种方式处理。方法调用工作正常。所以 theMeaningOfLife 在我的脚本中返回 nullgetTheMeaningOfLife() 返回 42。
  • 我想你的代表是一张地图或类似的东西。如果找不到密钥,让它抛出missingPropertyException。您的委托为 getProperty("meaningOfLife") 返回 null
猜你喜欢
  • 1970-01-01
  • 2011-10-24
  • 2011-05-19
  • 2013-07-09
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多