我怎样才能说服GroovyShell维持状态而不是eval()调用?

时间:2008-09-05 11:33:05

标签: java groovy scripting groovyshell

我正在尝试使用Groovy为我的应用程序创建交互式脚本/宏模式。该应用程序是OSGi,脚本可能需要的大部分信息都不是预先知道的。我想我可以使用GroovyShell并在加载OSGi包时连续多次调用eval()。 GroovyShell维护多个eval调用的变量状态,但不维护类定义或方法。

目标:在启动期间创建基类。当OSGi捆绑加载时,根据需要创建派生类。

3 个答案:

答案 0 :(得分:2)

我不确定你对eval之间不存在的声明类的含义是什么,以下两个脚本在逐个传播时按预期工作:

class C {{println 'hi'}}
new C()

...

new C()

然而,方法被绑定到声明它们的类,GroovyShell为每个实例创建一个新类。如果您不需要任何脚本的返回值,并且它们是真正的脚本(不是具有主要方法的类),您可以将以下内容附加到每个已评估的脚本的末尾。

Class klass = this.getClass()
this.getMetaClass().getMethods().each {
  if (it.declaringClass.cachedClass == klass) {
    binding[it.name] = this.&"$it.name"
  }
}

如果依赖于返回值,您可以手动管理评估并在解析过程中运行脚本(警告,未经测试的代码如下,仅供说明使用)...

String scriptText = ...
Script script = shell.parse(scriptText)
def returnValue = script.run()
Class klass = script.getClass()
script.getMetaClass().getMethods().each {
  if (it.declaringClass.cachedClass == klass) {
    shell.context[it.name] = this.&"$it.name"
  }
}
// do whatever with returnValue...

最后有一点需要注意,我相信你知道。静态类型变量不会在evals之间保留,因为它们不存储在绑定中。因此,在前面的脚本中,变量'klass'将不会保留在脚本调用之间并且将消失。为了纠正这种情况,只需在第一次使用所有变量时删除类型声明,这意味着它们将被读取并写入绑定。

答案 1 :(得分:1)

在每次脚本编译之前完成注入代码。最终目标是用户编写的脚本具有可供使用的特定于域的语言。

答案 2 :(得分:0)

这可能就是你要找的东西?

来自Groovy in Action

def binding = new Binding(x: 6, y: 4)
def shell = new GroovyShell(binding)
def expression = '''f = x * y'''
shell.evaluate(expression)
assert binding.getVariable("f") == 24

适当使用Binding可以让你保持状态吗?