如何保留来自evaluate的导入以使其可用于以下评估调用

时间:2018-01-15 11:06:39

标签: java groovy groovyshell

我有一个xml文件,包含groovy脚本文本,如下所示

<agent>
 <request id=1>
  <snippet>
   import java.util.regex.Matcher;
   import java.util.regex.Pattern;

   pageText = "My Page Text";
  </sniipet>
 </request>
 <request id=2>
  <snippet>

   Pattern matchlinkPat=Pattern.compile("callEvent",Pattern.MULTILINE);
   Matcher match = matchlinkPat.matcher(pageText);

  </sniipet>
 </request>
</agent>

我正在评估来自我的Java类的<snippet>标记中的字符串文本,如下所示

//Inside my Java Class
Binding binding = new Binding();
GroovyShell groovyshell = new GroovyShell(binding);

//Iterate each snippet tag and evaluate the script code
public Object evaluate(String code) {
    return groovyshell.evaluate(code);
}

评估第一个代码段,但第二个代码段无法评估。

如果我重新声明第二个代码段中的导入,则会对其进行评估而不会出现任何错误。

有什么方法可以让我的导入可用于以下片段文本?

1 个答案:

答案 0 :(得分:3)

不,这是不可能的,因为GroovyShell.evaluate(String script)使用传递String的代码创建一个Groovy脚本类,然后运行它。

/**
 * Evaluates some script against the current Binding and returns the result
 *
 * @param codeSource
 * @throws CompilationFailedException
 */
public Object evaluate(GroovyCodeSource codeSource) throws CompilationFailedException {
    Script script = parse(codeSource);
    return script.run();
}

来源:https://github.com/groovy/groovy-core/blob/GROOVY_2_4_X/src/main/groovy/lang/GroovyShell.java#L590

每个脚本都是独立运行的,因此Groovy shell不会记录以前的评估所做的事情 - 每个脚本都以一个全新的脚本开始,带有绑定,您将构造函数参数传递给GroovyShell类构造函数。这就是为什么你的导入永远不会出现在第二个片段中。基本上没有显式导入的第二个片段是没用的 - 在这种情况下,Groovy shell的行为正确。

Groovy脚本绑定

您在评论中询问为什么第一个代码段中的pageText在第二个代码段中可见。这是因为Groovy脚本使用bindings机制来存储和检索变量。 Groovy的Script类以下列方式覆盖getProperty(String property)setProperty(String property, Object value)方法:

public Object getProperty(String property) {
    try {
        return binding.getVariable(property);
    } catch (MissingPropertyException e) {
        return super.getProperty(property);
    }
}

public void setProperty(String property, Object newValue) {
    if ("binding".equals(property))
        setBinding((Binding) newValue);
    else if("metaClass".equals(property))
        setMetaClass((MetaClass)newValue);
    else
        binding.setVariable(property, newValue);
}

来源:https://github.com/apache/groovy/blob/master/src/main/groovy/groovy/lang/Script.java#L54

正如您所看到的,当您尝试在Groovy脚本中访问变量或尝试为脚本中的变量赋值时,它会从bindings对象中检索并存储此信息(您可以认为关于bindings对象作为Map<String, Object>)。并且因为您使用相同的GroovyShell实例评估两个片段,所以两个脚本都使用相同的bindings对象。这就是为什么第一个代码段中的pageText存储在bindings对象中的原因,当您在第二个代码段中使用此变量时,它会从bindings得到解决而没有任何问题。