转载

Java中使用Groovy实现自定义表达式解析

Groovy作为一种JVM-Based语言,目前普及程度正在提高。本文演示一下在Java类中,通过继承GDK的groovy.lang.Script类如何支持自定义表达式解析功能。

输入:

表示一行数据的某个map结构。在实际应用中,产生这种结构的最常见场景可能是通过JDBC访问数据库、通过调用WebService服务得到的某行结果集等。

目标设定:

假设我们希望对输入数据进行某个运算。此处示例中,我们模拟oracle中最常用的nvl函数。

处理过程:

首先,通过继承groovy.lang.Script,定义自己的表达式解析类:

public class MyBasicScript extends Script

在该类中实现具体的解析方法:

public static Object nvl(Object str,Object val){   return str==null ||"".equals(str)?val:str; }

其次,基于上述自定义类,实例化一个CompilerConfiguration对象。

CompilerConfiguration cfg = new CompilerConfiguration(); cfg.setScriptBaseClass(MyBasicScript.class.getName());

以此CompilerConfiguration实例为参数,实例化一个GroovyShell对象

shell = new GroovyShell(cfg);

通过shell对象,解析并运行表达式。在运行前,可以通过bingding对象绑定脚本运行时的上下文数据:

Binding binding = new Binding(map); Script script = shell.parse(expr); script.setBinding(binding); script.run();

附完整的代码示例(共两个类,分别是自定义脚本实现类、调用及测试类)

package jg.groovy;  import groovy.lang.Script;  import java.lang.reflect.Method;  public class MyBasicScript extends Script  {   @Override  public Object run() {   //show usage   Method[] methods = MyBasicScript.class.getDeclaredMethods();   StringBuilder sb=new StringBuilder();   for (Method method : methods) {    sb.append(method);   }      return sb.substring(0, sb.length()-1);  }    public static Object nvl(Object str, Object val) {   return str == null || "".equals(str) ? val : str;  }  }
package jg.groovy;  import groovy.lang.Binding; import groovy.lang.GroovyShell; import groovy.lang.Script;  import java.util.HashMap; import java.util.Hashtable; import java.util.Map;  import org.codehaus.groovy.control.CompilerConfiguration;  public class ExprSupport {   private static final Object lock = new Object();  private static final GroovyShell shell;   private static Hashtable<String, Script> cache = new Hashtable<String, Script>();  static {   CompilerConfiguration cfg = new CompilerConfiguration();   cfg.setScriptBaseClass(MyBasicScript.class.getName());     shell = new GroovyShell(cfg);  }   public static Object parseExpr(String expr) {   Script s = getScriptFromCache(expr);   return s.run();  }   public static Object parseExpr(String expr, Map<?, ?> map) {   Binding binding = new Binding(map);   Script script = getScriptFromCache(expr);   script.setBinding(binding);   return script.run();  }   private static Script getScriptFromCache(String expr) {   if (cache.contains(expr)) {    return cache.get(expr);   }   synchronized (lock) {    if (cache.contains(expr)) {     return cache.get(expr);    }    Script script = shell.parse(expr);    cache.put(expr, script);    return script;   }  }   /**   * @param args   */  public static void main(String[] args) {    // eg. get one row from db   Map<String, Object> row = new HashMap<String, Object>();   row.put("id", 42);   row.put("name", "");      //带绑定数据参数的调用方式   System.out.println(ExprSupport.parseExpr("nvl(id,0)", row));   System.out.println(ExprSupport.parseExpr("nvl(name,'anonymous')", row));      //不带绑定数据参数的调用方式,这个是groovy的内置能力   System.out.println(ExprSupport.parseExpr("1+2"));   }  }

输出:

42 anonymous 3

总结:结合groovy对表达式的内置支持能力与自定义脚本能力,可以实现功能强大的表达式解析能力。

正文到此结束
Loading...