编译用户在运行时输入groovy脚本

时间:2015-08-24 05:19:56

标签: grails groovy

如下所示,我需要验证groovy脚本的正确性。

// Serialize all menu items before submit
function serialize_menu_items(){
    $("ul li").each(function(e){
        this_index = $(this).index();
        parent_index = $(this).parents('li').find(".link_id:first").val();
        if(parent_index === -1 || typeof parent_index == "undefined") { parent_index = 0; }

        $(this).find(".parent_link_id:first").val(parent_index);
        $(this).find(".sortorder:first").val(this_index);
    });
}

上面代码中的问题是它运行代码,如果有任何异常,它会在运行时抛出它。

要考虑的事情很少:

  1. groovy代码应该编译而不是运行(因为代码可能包含数据库级别更新)并抛出异常。
  2. groovy代码应该静态编译,例如,如果我们在脚本中缺少某些属性,则必须得到通知。
  3. 下面的

    可以是示例脚本:

    class CostCalculator{
    
    String name
    String groovyScript
    
    static constraints = {
    groovyScript:static validateScript = {String script ,def obj->
            boolean status = true
            try {
                def shell = new GroovyShell()
                def data = shell.parse(script)
                data.run()
            }catch (Throwable e){
                e.printStackTrace()
                status = false
            }
            if(!status){
                return "domain.script.compilation.errors"
            }else{
                return true
            }
        }
    }
    
    }
    

1 个答案:

答案 0 :(得分:1)

我建议将你的groovy脚本放在一个类中。

在示例中,您有方法 addCost(),所以我想说只需将此方法包装在一个类中。例如:

String gScript = """
class CostCalculatorScript{
    void addCost(int x, int y,String itemName){
        double cost = x*y + originalCost
        Item item = SoldItem.findByItemName(itemName)
        item.price += cost
    }
}

"""

现在使用GroovyClassLoader加载并解析此脚本。

ClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass(gScript)

验证加载的类是否与您在脚本中指定的名称相同。

assert clazz.simpleName == 'CostCalculatorScript'

现在你想要的那种解决方案看起来像是静态编译。您可以将 @ groovy.transform.CompileStatic 注释添加到您的班级。但是通过这个注释,问题在于你无法使用grails的动态查找器或def关键字。

但是如果您仍然需要该功能,那么您应该使用Grails 2.4中提供的 @grails.compiler.GrailsCompileStatic 注释。