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對表達式的內置支持能力與自定義腳本能力,可以實現功能強大的表達式解析能力。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM