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

How to preserve imports from evaluate to make it available for following evaluate calls

我有一个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 class 中 <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);
}

第一个代码片段得到评估,但第二个代码片段评估失败。

如果我在第二个片段中重新声明导入,它会在没有任何错误的情况下得到评估。

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

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

/**
 * 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 不会记录之前的评估做了什么 - 每个脚本都是作为一个全新的脚本开始的,你将一个构造函数参数传递给 [=13] =] class 构造函数。这就是为什么您的导入从未出现在第二个片段中的原因。基本上没有显式导入的第二个片段是无用的 - Groovy shell 在这种情况下表现正确。

Groovy 脚本绑定

您在评论中询问了为什么第一个片段中的 pageText 在第二个片段中可见。这是因为 Groovy 脚本使用 bindings 机制来存储和检索变量。 Groovy 的 Script class 按以下方式覆盖 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 脚本中的变量或尝试为脚本中的变量赋值时,它都会从 [=18= 中检索并存储此信息] 对象(您可以将 bindings 对象视为 Map<String, Object>)。因为您使用相同的 GroovyShell 实例评估两个片段,所以两个脚本都使用相同的 bindings 对象。这就是为什么第一个代码段中的 pageText 存储在 bindings 对象中,当您在第二个代码段中使用此变量时,它会从 bindings 中毫无问题地解析。