JEXL 简介

来源:org.apache.commons.jexl3 (Apache Commons JEXL 3.2.1 API)

JEXL 是一个表达式语言引擎,可以在应用程序或框架中实现动态和脚本功能。

一个简单的例子:

// 创建 JexlEngine (可以重用)
JexlEngine jexl = new JexlBuilder().create();

// 创建一个表达式对象 'car.getEngine().checkStatus()':
String jexlExp = "car.engine.checkStatus()";
Expression e = jexl.createExpression( jexlExp );

//car 作为一个入参管理
Car car = theCarThatWeHandle;

// 创建一个contenxt,并且添加数据
JexlContext jc = new MapContext();
jc.set("car", car );

// 现在计算表达式,得到结果
 Object o = e.evaluate(jc);

使用JEXL

Jexl API 由三个级别组成,满足不同的功能需求:

  1. setter、getter、方法和构造函数的动态调用;
  2. JEXL表达式的脚本表达式
  3. 类似JSP/JSF的表达式,称为JXLT表达式

注意事项

公共的API位于以下两个包中:

  • org.apache.commons.jexl3
  • org.apache.commons.jexl3.introspection

以下包这些仅用于扩展JEXL。它们的类和方法不能保证在后续版本中保持兼容。如果你认为你需要直接使用他们的一些功能或方法,最好先通过邮件列表与社区联系。

  • org.apache.commons.jexl3.parser
  • org.apache.commons.jexl3.scripting
  • org.apache.commons.jexl3.internal
  • org.apache.commons.jexl3.internal.introspection

动态调用

这些功能与BeanUtils中的核心级实用程序非常接近。对于基本的动态属性操作和方法调用,可以使用以下一组方法:

下面的示例说明了它们的用法:

// test outer class
public static class Froboz {
      int value;
      public Froboz(int v) { value = v; }
      public void setValue(int v) { value = v; }
      public int getValue() { return value; }
 }
// test inner class
public static class Quux {
       String str;
       Froboz froboz;
       public Quux(String str, int fro) {
            this.str = str;
            froboz = new Froboz(fro);
       }
 public Froboz getFroboz() { return froboz; }
 public void setFroboz(Froboz froboz) { this.froboz = froboz; }
 public String getStr() { return str; }
 public void setStr(String str) { this.str = str; }
}
            // test API
  JexlEngine jexl = new JexlBuilder().create();
  Quux quux = jexl.newInstance(Quux.class, "xuuq", 100);
  jexl.setProperty(quux, "froboz.value", Integer.valueOf(100));
  Object o = jexl.getProperty(quux, "froboz.value");
  assertEquals("Result is not 100", new Integer(100), o);
  jexl.setProperty(quux, "['froboz'].value", Integer.valueOf(1000));
  o = jexl.getProperty(quux, "['froboz']['value']");
  assertEquals("Result is not 1000", new Integer(1000), o);

表达式和脚本

如果需要简单的表达式评估功能,JEXL的核心特性很可能适合。主要的方法有:

下面的示例说明了他们的用法:

           JexlEngine jexl = new JexlBuilder().create();

            JexlContext jc = new MapContext();
            jc.set("quuxClass", quux.class);

            JexlExpression create = jexl.createExpression("quux = new(quuxClass, 'xuuq', 100)");
            JelxExpression assign = jexl.createExpression("quux.froboz.value = 10");
            JexlExpression check = jexl.createExpression("quux[\"froboz\"].value");
            Quux quux = (Quux) create.evaluate(jc);
            Object o = assign.evaluate(jc);
            assertEquals("Result is not 10", new Integer(10), o);
            o = check.evaluate(jc);
            assertEquals("Result is not 10", new Integer(10), o);

统一表达式和模板

如果您正在寻找类似JSP-EL的基本模板功能,可以使用JxltEngine中的Expression。

主要的方法有:

下面的示例说明了他们的用法:

            JexlEngine jexl = new JexlBuilder().create();
            JxltEngine jxlt = jexl.createJxltEngine();
            JxltEngine.Expression expr = jxlt.createExpression("Hello ${user}");
            String hello = expr.evaluate(context).toString();

JexlExpression, JexlScript, Expression and Template

JexlExpression

这些是JexlEngine表达式的最基本形式,只允许执行单个命令并返回结果。如果您尝试使用多个命令,它会忽略第一个分号之后的所有内容,只返回第一个命令的结果。

还要注意,表达式不是语句(这是脚本的组成部分),不允许使用流控制(if,while,for)、变量或lambdas语法元素。

JexlScript

这些允许您使用多个语句,您可以使用变量赋值、循环、计算等。或多或少可以在Shell或JavaScript的基本级别实现这些功能。最后一个命令的结果从脚本返回。

JxltEngine.Expression

这些是生成“一行”文本的理想选择,比如类固醇的“toString()”。要获得计算,可以使用类似于EL的语法,如${someVariable}。括号之间的表达式的行为类似于JexlScript,而不是表达式。您可以使用分号来执行多个命令,最后一个命令的结果将从脚本返回。您还可以使用#{someScript}语法使用两遍评估。

JxltEngine.Template

它们生成文本文档。以“$$”(默认值)开头的每一行都被视为JEXL代码,其他所有行都被认为是JxltEngine.Expression。将这些视为简单的Velocity模板。重写的MudStore初始Velocity示例如下所示:

        <html>
            <body>
                Hello ${customer.name}!
                <table>
        $$      for(var mud : mudsOnSpecial ) {
        $$          if (customer.hasPurchased(mud) ) {
                    <tr>
                        <td>
                            ${flogger.getPromo( mud )}
                        </td>
                    </tr>
        $$          }
        $$      }
        </table>
        </body>
        </html>

JEXL 配置

JexlEngine可以通过几个参数进行配置,这些参数将驱动它在发生错误时的反应。这些配置方法通过JexlBuilder嵌入。

静态共享配置

JexlEngine和JxltEngine都是线程安全的,它们的大部分内部字段都是final;同一实例可以在不同线程之间共享,并且在关键区域(内省缓存)中强制执行适当的同步。

特别重要的是JexlBuilder.loader,它指示正在构建的JexlEngine使用哪个类加载器来解决类名;这直接影响JexlEngine.newInstance和“new”脚本方法的操作方式。

在依赖JEXL为应用程序动态加载和调用插件的情况下,这也非常有用。为了避免在插件实现发生更改时重新启动服务器,您可以调用JexlEngine.setClassLoader(java.lang.ClassLoader),通过该引擎实例创建的所有脚本都将自动指向新加载的类。

您可以通过NoJexl注释说明可以通过脚本操作什么,该注释完全屏蔽了类和方法,使其不受JEXL内省的影响。限制JEXL的另一种可配置方式是使用JexlSandbox,它允许更好地控制暴露的内容;沙盒可以通过JexlBuilder.sandbox设置。

命名空间(java.util.Map<java.lang.String,java.lang.Object>)通过将自己的类注册为命名空间来扩展JEXL脚本,允许随意公开自己的函数。

这可用于

            public static MyMath {
                public double cos(double x) {
                    return Math.cos(x);
                }
            }
            Map<String, Object> funcs = new HashMap<String, Object>();
            funcs.put("math", new MyMath());
            JexlEngine jexl = new JexlBuilder().namespaces(funcs).create();

            JexlContext jc = new MapContext();
            jc.set("pi", Math.PI);

            JexlExpression e = JEXL.createExpression("math:cos(pi)");
            o = e.evaluate(jc);
            assertEquals(Double.valueOf(-1),o);

默认支持的操作:

OperatorMethod NameExample
+addadd(x, y)
-subtractsubtract(x, y)
*multiplymultiply(x, y)
/dividedivide(x, y)
%modmod(x, y)
&bitwiseAndbitwiseAnd(x, y)
|bitwiseOrbitwiseOr(x, y)
^bitwiseXorbitwiseXor(x, y)
!logicalNotlogicalNot(x)
-bitwiseComplementbitiwiseComplement(x)
==equalsequals(x, y)
<lessThanlessThan(x, y)
<=lessThanOrEquallessThanOrEqual(x, y)
>greaterThangreaterThan(x, y)
>=greaterThanOrEqualgreaterThanOrEqual(x, y)
-negatenegate(x)
sizesizesize(x)
emptyemptyempty(x)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值