Groovy 脚本变量引用自动化分析

groovy因为其动态性经常被用来维护一些经常变化的业务规则,嵌入到应用中执行,达到可以灵活变更维护效果。 如如下脚本:

if(order.containsAttribute("test"))
           return "AFTER_PAY"
           if(isCOD)
           return "BEFORE_PAY"

通过分析,可以得出以上脚本需要传入参数 orderisCOD. 使用以上脚本时会带来一个问题,调用者需要分析才可得出orderisCOD两个变量。 尤其对于一个长的规则脚本来说,人为分析更是麻烦且容易出错。如果能自动分析并得到结果会更好。

基于此研究了下groovy的AST树分析的vistor模式,可以实现自动分析出脚本里需要的信息。如变量应用。

1.编写一个自定义的vistor


           import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
           import org.codehaus.groovy.ast.DynamicVariable;
           import org.codehaus.groovy.ast.expr.Expression;
           import org.codehaus.groovy.ast.expr.MethodCallExpression;
           import org.codehaus.groovy.ast.expr.VariableExpression;
           import org.codehaus.groovy.control.SourceUnit;
           
           import java.util.HashSet;
           import java.util.Set;
           
           /**
           * @since 14-4-14
           */
           public class CustomGroovyVistor extends ClassCodeVisitorSupport {
           
           private Set<String> dynamicVariables = new HashSet<String>();
           private Set<String> methodNames = new HashSet<String>();
           
           
           /**覆写父类的方法,实现对变量节点的分析和记录**/
           public void visitVariableExpression(VariableExpression expression) {    //变量表达式分析
           super.visitVariableExpression(expression);
           Expression e = expression.getInitialExpression();
           if (expression.getAccessedVariable() instanceof DynamicVariable) {
           dynamicVariables.add(expression.getName());
           }
           }
           
           public void visitMethodCallExpression(MethodCallExpression call) {
           super.visitMethodCallExpression(call);
           String methodName = call.getMethodAsString();
           if (methodName != null && methodName.startsWith("f_")) {
           methodNames.add(call.getMethodAsString());
           }
           }
           
           @Override
           protected SourceUnit getSourceUnit() {
           return null;
           }
           
           public Set<String> getDynamicVariables() {
           return dynamicVariables;
           }
           
           public void setDynamicVariables(Set<String> dynamicVariables) {
           this.dynamicVariables = dynamicVariables;
           }
           
           public Set<String> getMethodNames() {
           return methodNames;
           }
           
           public void setMethodNames(Set<String> methodNames) {
           this.methodNames = methodNames;
           }
           }

2.构建使用AST 树Node,使用自定义vistor分析树

String script="..."
           List<ASTNode> nodes = new AstBuilder().buildFromString(script);
           CustomGroovyVistor variableScopeVisitor = new CustomGroovyVistor();
           for (ASTNode node : nodes) {
           node.visit(variableScopeVisitor);
           }
           for(String v:variableScopeVisitor.getDynamicVariables()){
           System.out.println(v);
           }

以上结果即可得到该脚本的变量引用