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

原文链接: https://my.oschina.net/u/2426551/blog/1537437

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

 

输入:

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

目标设定:

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


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

1

public class MyBasicScript extends Script

  

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

1

2

3

public static Object nvl(Object str,Object val){

  return str==null ||"".equals(str)?val:str;

}

 

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

1

2

CompilerConfiguration cfg = new CompilerConfiguration();

cfg.setScriptBaseClass(MyBasicScript.class.getName());

  

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

1

shell = new GroovyShell(cfg);  

  

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

 

1

2

3

4

Binding binding = new Binding(map);

Script script = shell.parse(expr);

script.setBinding(binding);

script.run();

  

 

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

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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;

    }

 

}

  

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

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 cache = new Hashtable();

    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 row = new HashMap();

        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"));

 

    }

 

}

  

  输出:

1

2

3

42

anonymous

3

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

转载于:https://my.oschina.net/u/2426551/blog/1537437

你可能感兴趣的:(Java中使用Groovy实现自定义表达式解析)