2017-08-09 100 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

相關問題