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对表达式的内置支持能力与自定义脚本能力,可以实现功能强大的表达式解析能力。

posted @ 2015-05-03 12:38  GString  阅读(15160)  评论(0编辑  收藏  举报