2017-08-09 98 views
2

我想嵌入Groovy以在我的Java应用程序中启用脚本功能。我想使用静态类型检查,此外我想传递一些额外的(全局)变量到脚本。下面是我的配置:嵌入式Groovy:如何对外部变量使用静态类型检查?

String script = "println(name)"; // this script was entered by the user 

    // compiler configuration for static type checking 
    CompilerConfiguration config = new CompilerConfiguration(); 
    config.addCompilationCustomizers(new ASTTransformationCustomizer(CompileStatic.class)); 

    // compile the script 
    GroovyShell shell = new GroovyShell(config); 
    Script script = shell.parse(script); 

    // later, when we actually need to execute it... 
    Binding binding = new Binding(); 
    binding.setVariable("name", "John"); 
    script.setBinding(binding); 
    script.run(); 

正如你所看到的,用户提供的脚本使用全局变量name,它是通过注射script.setBinding(...)。现在有一个问题:

  • 如果我在用户脚本(例如String name;)声明变量name,则绑定没有效果因为变量已经在脚本存在。
  • 如果我没有在脚本中声明变量,静态类型检查器将(正确)抱怨name未被声明。

问题是:我该如何解决这个问题?如何告诉类型检查器脚本在被调用时会接收到某种类型的全局变量?

回答

1

doc, 可以使用extensions参数,

config.addCompilationCustomizers(
    new ASTTransformationCustomizer(
     TypeChecked, 
     extensions:['robotextension.groovy']) 
) 

然后加入robotextension.groovy到类路径:

unresolvedVariable { var -> 
    if ('name'==var.name) { 
     storeType(var, classNodeFor(String)) 
     handled = true 
    } 
} 

在这里,我们告诉编译器,如果找到一个未解决的变量,并且该变量的名称是名称,那么我们可以确定这个变量的类型是String

+1

我只想补充一点,可以用'String name = this.binding.variables.name'这样的东西来预先给用户脚本,这也可以满足类型检测器。然而,缺点是修改用户脚本会弄乱类型检查器报告的行号,所以你的解决方案很可能是更好的解决方案。 – Alan47

相关问题