Java中使用Groovy實現自定義表達式解析

me87re 9年前發布 | 51K 次閱讀 Groovy Java開發


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

來自:http://www.cnblogs.com/ora11g/p/4473544.html

 本文由用戶 me87re 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!