【问题标题】:Get expression values in JEXL在 JEXL 中获取表达式值
【发布时间】:2020-01-30 07:13:26
【问题描述】:

具有以下 JEXL 表达式:

String expression = "myVar >= 12345 && mySecondVar <= 56789";

我可以调用 createScript 和 getVariables 来获取 myVar 和 mySecondVar 作为值,例如:

Set<List<String>> expressionVars = JEXL.createScript(expression).getVariables();

我想知道的是,如果给定相同的表达式,我可以调用一些其他方法来返回这些变量的值。原因是我想验证其中一些值的输入。我检查了文档并使用了 JexlScript 类,但找不到一种优雅的方法。 由于 JEXL 已经在解析我的表达式,如果能够检索到这些信息,而不必手动解析我的表达式来获取这些值,那就太棒了。

script.getValue("myVar"); 的行中返回 12345

【问题讨论】:

    标签: java jexl


    【解决方案1】:

    使用 JEXL,您可以在包含变量及其值的给定上下文 (JexlContext) 中评估脚本/表达式。 JexlContext 公开了 'has' 和 'get' 方法,它们分别检查是否存在并获取变量的值。 在您的情况下,您需要找出您的 JexlContext 是(或应该是);从那里,可以直接迭代您的变量(从脚本中提取)并检查它们的值(从上下文中)。

    见: http://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/JexlContext.html http://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/JexlScript.html

    例如(使用来自https://github.com/apache/commons-jexl 的 JEXL 3.2 中继):

    /**
     * Collect the global variables of a script and their values from a context.
     * @param script the script
     * @param context the context
     * @return a map keyed by variable name of their contextual values
     */
    Map<String, Object> collectVars(JexlScript script, JexlContext context) {
        Set<List<String>> sls = script.getVariables();
        Map<String, Object> vars = new TreeMap<String, Object>();
        for(List<String> ls : sls) {
            // build the 'antish' name by concatenating
            StringBuilder strb = new StringBuilder();
            for(String s : ls) {
                if (strb.length() > 0) {
                    strb.append('.');
                }
                strb.append(s);
            }
            String name = strb.toString();
            vars.put(name, context.get(name));
        }
        return vars;
    }
    
    @Test
    public void testStckOvrflw() throws Exception {
        JexlEngine jexl = new JexlBuilder().safe(false).create();
        // a context with some variables
        JexlContext context = new MapContext();
        context.set("low", 15000);
        context.set("high", 50000);
        context.set("mid", 35000);
        context.set("limit.low", 15042);
        context.set("limit.high", 35042);
        // an expression with 2 variables
        JexlScript expr = jexl.createScript("low >= 12345 && high <= 56789");
        // collecting the 2 variables, low and high
        Map<String, Object> vars = collectVars(expr, context);
        Assert.assertEquals(2, vars.size());
        Assert.assertEquals(15000, vars.get("low"));
        Assert.assertEquals(50000, vars.get("high"));
    
        expr = jexl.createScript("limit.low >= 12345 && limit.high <= 56789");
        vars = collectVars(expr, context);
        Assert.assertEquals(2, vars.size());
        Assert.assertEquals(15042, vars.get("limit.low"));
        Assert.assertEquals(35042, vars.get("limit.high"));
    }
    

    【讨论】:

    • 你能举个例子吗?
    • 提供示例。
    【解决方案2】:

    您应该实现自己的上下文:

    public class ZenContext implements JexlContext {
      static private final Map<String, Object> reservedVars = new HashMap<String, Object>();
      private final Map<String, Object> scriptDefinedVars  = new HashMap<String, Object>();
      static {
        reservedVars.put("math", java.lang.Math.class);
        reservedVars.put("stats", apache.commons.math3.stats.Stats);
        // whatever else ...
      }
    
      public boolean has(String name) {
        if (reservedVars .get(name) != null) return true;
        return scriptDefinedVars.get(name) != null;
      }
    
      public boolean get (String name) {
        Object value = null;
        if ((value = reservedVars .get(name)) != null) return value;
    
        return scriptDefinedVars.get(name);
      }
    
      public void set(String name, Object value) {
        scriptDefinedVars.set(name, value);
      }
    
      public Map<String, Object> getReservedVars () {
        return reservedVars;
      }
      public Map<String, Object> getScriptDefinedVars   () {
        return scriptDefinedVars ;
      }
    }
    

    这样,你就有了

    • 保留 var 名称的映射以包含不允许脚本更改其值的对象。例如,
    • 可通过脚本设置的独立变量映射。

    然后添加这些方法。

    public Object execute(File scriptFile) {
        JexlScript script = jexlEngine.createScript(scriptFile);
        return script.execute(this); // supply this as the context 
    }
    public Object execute (String scriptText) {
        JexlScript script = jexlEngine.createScript(scriptText);
        return script.execute(this); // supply this as the context 
    }
    

    您可以修改我在这里编写的 set 方法,在允许设置之前检查映射中的变量。

    但是,这不适用于本地脚本变量

    var greeting = 'The rain in Maine falls plainly insane';
    

    因为本地 var 依赖于不同的机制,org.apache.commons.jexl3.internal.Scope,使用 getLocalVariables() 方法,它有一个错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多