转载自   利用JEXL实现动态表达式编译

背景

做项目突然遇到这样的需求:
系统要获取多个数据源的数据,并进行处理,最后输出多个字段。字段的计算规则一般是简单的取值最多加一点条件判断。
而且需要动态变动!!例如一个字段a的取值,如果a > 10的时候输出10,a <= 10则输出a。这里的10可能在一天后改成8,也可能在后天就改成了12。当然,如果只是一个数字的变动还好说,我们可以使用数据库进行存储。但是,万一哪天需求突然变成了a < 10的时候输出10,a >=10 则输出a,就需要对代码改动,再测试再发布才能到生产环境使用。
一两个这样的字段还没什么,如果整个系统所依赖的字段都有这样的属性,那么我们就需要找一种方法来实现动态的加载逻辑。
下面介绍的JEXL就可以解决这种问题

JEXL(Java Expression Language)介绍

JEXL – Apache Commons JEXL Overview
下面用一些实例来介绍JEXL的使用方法

实例

maven依赖:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-jexl</artifactId><version>2.0</version>
</dependency>

正则表达式匹配

首先写一个公共方法:

public class Util {public static boolean regMatch(String regEx, String str) {Pattern pattern = Pattern.compile(regEx);return pattern.matcher(str).matches();}
}

下面是使用JEXL调用的方法

public void RL() {JexlContext jc = new MapContext();String str = "一二三四五六七八九十";jc.set("Util", new Util());jc.set("str", str);jc.set("ans", "");String expression = "ans = Util.regMatch(\"[\u4e00-\u9fa5]{10,}\",str)";Expression e = new JexlEngine().createExpression(expression);e.evaluate(jc);System.out.println(jc.get("ans"));
}

代码中的expression变量就是可以动态编译的表达式,这里要注意表达式中出现的所有变量,都需要事先set进JexlContext中,否则会报错。这里有多种形式的错误:
①如果没有set”Util”,程序运行中会抛出异常。

org.apache.commons.jexl2.JexlException: TmpTest.RL@40![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' attempting to call method on null

②如果没有set”str”,程序不会抛出异常,并输出null。如果你的regMatch方法中有判空处理,就会输出判空的结果。如果没有判空处理,在控制台的输出如下:

警告: TmpTest.RL@39![36,39]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' undefined variable str
二月 21, 2017 4:00:41 下午 org.apache.commons.jexl2.JexlEngine invocationFailed
警告: TmpTest.RL@39![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' method invocation error
java.lang.NullPointerException

③如果没有set”ans”,程序会正常运行,并输出正确值
为了保险起见,建议表达式中出现的所有变量,都需要事先set进JexlContext中

循环

JEXL支持两种循环方式:

for(item : list) {x = x + item;
}

while (x lt 10) {x = x + 2;
}

下面是使用while的实例:

public void loop() {JexlContext jc = new MapContext();jc.set("a", 1);jc.set("b", "0");jc.set("ans", new StringBuffer());Expression e = new JexlEngine().createExpression("while (a < 10) {a = a + 1;ans.append(b);}");e.evaluate(jc);System.out.println(jc.get("ans"));
}

get\set方法调用

JEXL支持传入对象,并调用对象的方法
下面的简单的get\set方法的实例:

public void getSet() {TmpTest tmpTest = new TmpTest();tmpTest.setA(1);JexlContext jc = new MapContext();jc.set("tmpTest", tmpTest);jc.set("ans", "");Expression e = new JexlEngine().createExpression("ans = tmpTest.getA()");e.evaluate(jc);System.out.println(jc.get("ans"));e = new JexlEngine().createExpression("ans = tmpTest.setA(2)");e.evaluate(jc);TmpTest tmpTest1 = (TmpTest) jc.get("tmpTest");System.out.println(tmpTest1.getA());
}

上面的用例会在控制台先输出1,再输出2

利用JEXL实现动态表达式编译相关推荐

  1. 找不到编译动态表达式所需的一种或多种类型。是否缺少对 Microsoft.CSharp.dll 和 System.Core.dll 的引用?...

    提示"找不到编译动态表达式所需的一种或多种类型.是否缺少对 Microsoft.CSharp.dll 和 System.Core.dll 的引用? "错误 解决方法:   将引入的 ...

  2. jboss fuse 教程_JBoss Fuse:使用JEXL的动态蓝图文件

    jboss fuse 教程 在本文中,我将展示如何在Apache Aries Blueprint xml文件中添加一些内联脚本. 我不一定会称其为最佳实践,但我一直有这样的想法:这种能力可能有用. 可 ...

  3. JBoss Fuse:使用JEXL的动态蓝图文件

    在本文中,我将展示如何在Apache Aries Blueprint xml文件中添加一些内联脚本. 我不一定会称其为最佳实践,但我一直认为这种功能可能有用. 可能当我被迫使用xml来模拟命令式编程结 ...

  4. 代码生成(Code Generation) 表达式编译

    代码生成(Code Generation)技术广泛应用于现代的数据系统中.代码生成是将用户输入的表达式.查询.存储过程等现场编译成二进制代码再执行,相比解释执行的方式,运行效率要高得多.尤其是对于计算 ...

  5. 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)

    原文:利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...

  6. 解答网友提问:如何构建动态表达式实现高级查询服务

    上次我们介绍了"一秒创建高级查询服务".前天,有网友在公众号后台问我,怎么使用动态表达式: 我想应该是客户提出了更高的要求,查询的条件不仅限于大于.小于,更加多样化,需要动态组合成 ...

  7. Unix/Linux操作系统分析实验二 内存分配与回收:Linux系统下利用链表实现动态内存分配

    Unix/Linux操作系统分析实验一 进程控制与进程互斥 Unix/Linux操作系统分析实验三 文件操作算法: 实现在/proc目录下添加文件 Unix/Linux操作系统分析实验四 设备驱动: ...

  8. AICompiler动态shape编译框架

    AICompiler动态shape编译框架 移动互联网的兴起,不仅产生了海量数据,也对人机交互有了新的定义.企业如何动态处理不同规格图片数据,如何更灵活处理不同长度的对话语料等等,提升企业运营效率,争 ...

  9. php 循环写入 缓冲,php利用缓冲实现动态输出(flush,ob_flush)

    php利用缓冲实现动态输出通过 flush,ob_flush实现 print str_repeat(" ", 4096);//php.ini output_buffering默认是 ...

最新文章

  1. STD:Sparse-to-Dense 3D Object Detector for Point Cloud(腾讯香港大学)
  2. LINUX内核经典面试题30道及解答
  3. linux hadoop集群搭建,hadoop集群搭建
  4. C++宏定义中#与##的妙用
  5. 虚拟机下CentOS7开启SSH连接
  6. 数据结构---递归实现十进制装换为任意进制
  7. UVA10168 Summation of Four Primes【筛选法】
  8. C# UDP 发送 接收
  9. mysql_affected_rows()、mysql_fetch_row、mysql_fetch_assoc
  10. 记redis的一个测试
  11. 古希腊神话故事1 :普罗米修斯
  12. 杭州计算机及应用不可以落户,90%的城市取消落户限制!附杭州落户超详细攻略...
  13. 什么是代理IP(代理服务器)如何正确使用代理IP(代理服务器)
  14. MAX9286+MAX96705高级辅助驾驶系统ADAS方案
  15. Android 快别用Toast了,来试试Snackbar
  16. 网页聊天框发送表情图片实现方法
  17. 基于Matlab的开环Buck降压斩波电路Simulink仿真电路模型搭建
  18. 阅读笔记--操作系统(清华大学公开课)
  19. 属性表中的 <空> 空格 和 空白
  20. 宇视2016c语言招聘试题,宇视科技2016招聘试题.docx

热门文章

  1. leetcode406. 根据身高重建队列
  2. leetcode18. 四数之和(双指针)
  3. PHP做二次开发:本机安装ThinkCMF系统
  4. python注入进程_向进程中注入Python代码
  5. matlab中scrsz的意思,matlab图片c存储方法
  6. Codeforces Round #538 (Div. 2) F. Please, another Queries on Array? 线段树 + 欧拉函数
  7. Educational Codeforces Round 80 (Rated for Div. 2) E. Messenger Simulator 思维 + 树状数组
  8. Codeforces Round #717 (Div. 2) D(倍增dp)
  9. P3825 [NOI2017]游戏
  10. P2257 YY的GCD