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

时间: 2024-08-24 12:49:08

Java中使用Groovy实现自定义表达式解析的相关文章

23 在java中使用groovy类

1       在java中使用groovy类 1.1  直接调用groovy类 在java中调用Groovy类,需要增加Groovy运行时到java的classpath中. pom.xml <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.5</version> <

自定义表达式解析器

解析器: import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; imp

一个简单的Java模板工具类(二)—简单表达式解析实现

以前写过一个, 用正则比较不高效, 所以用表达式解析方式又实现了一个, 练手. 以前的: http://my.oschina.net/haogrgr/blog/222349 现在的: import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; /**  * 非常非常简单的模板实现  *   * @author desheng.tu  * @date 2015年

JAVA中的Random()函数解析

在软件开发中有时会遇到使用随机数的情况(部分验证码就是采用random生成的随机数).之前只知道怎么使用,一直没想过random的原理.前几天就记着去网上查一下这个问题,今天正好有时间,就从网上查阅了一些资料. Java中包含两类Random,一种是java.util.Random中的,采用的是伪随机(有规则的随机),相同种子数的Random对象,相同次数生成的随机数字是完全相同的.此Random类包括两个构造函数,public Random()和public Random(long seed)

java中的xml简介与DOM解析xml

1. xml简介 XML:指可扩展标记语言, Extensible Markup Language:类似HTML.XML的设计宗旨是传输数据,而非显示数据. 一个xml文档实例: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <company name="Tencent" address="深圳市南山区"> 3 <department deptNo=&quo

Java中的访问修饰符详细解析

1.类的修饰符分为:可访问控制符和非访问控制符两种. 可访问控制符是:公共类修饰符 public 非访问控制符有:抽象类修饰符 abstract :最终类修饰符 final 1 )公共类修饰符 public : Java 语言中类的可访问控制符只有一个: public 即公共的.每个 Java 程序的主类都必须是 public 类作为公共工具供其它类和程序使用的应定义为 public 类. 2 )抽象类修饰符 abstract :凡是用 abstract 修饰符修饰的类,被称为抽象类.所谓抽象类

java中一些容器底层的数据结构解析

先来看一个java里一些主要容器的继承图: 然后分别解析一下上面几种容器底层的数据结构以及一些实现: 1.ArrayList(非线程安全的) 底层的数据结构其实就是数组,但是它比数组优秀的地方在于他是动态的,即不必像数组那样固定大小,那么他是如何实现这种数据结构是数组,但是给我们看起来确实不固定大小的呢? ArrayList 是通过将底层 Object 数组复制的方式(System.arraycopy方法)来处理数组的增长: 当ArrayList 的容量不足时,其扩充容量的方式:先将容量扩充至当

使用Java中Comparator接口实现自定义排序

一般情况下,自己动手写一个简单排序程序还是没有问题的,但是你能保证写出来的排序程序的时间复杂度吗?你能保证程序的正确性吗,鲁棒性呢,还有程序结构的清晰性,可维护性.......综上所述,学习一下排序接口来实现对复杂对象的排序还是很有必要的.Java中有两个用来实现排序的接口Comparator和Comparable接口,本人比较喜欢使用java的Comparator接口,在程序里实现Comparator接口里的compare(Object o1,Object o2)方法,然后在程序中通过调用Ar

JAVA中sleep,wait,yield,join函数解析_ftc

线程退出最好自己实现,在运行状态中一直检验一个状态,如果这个状态为真,就一直运行,如果外界更改了这个状态变量,那么线程就停止运行. _____________________________________________________________________________________________________________________________________________________________________ 1.sleep()方法 在指定时间内