【问题标题】:creating context for MVEL with different variable types为具有不同变量类型的 MVEL 创建上下文
【发布时间】:2015-01-12 13:54:09
【问题描述】:

我正在使用 MVEL 来评估算术和逻辑表达式或两者的组合。问题是我事先并不知道所有变量类型,而没有为表达式本身创建一个非常复杂的解析方法(通过设置文件传递)。只有当我浏览我的数据并更新上下文时,我才知道它们的类型。 例如,考虑表达式(a && b) && (c == 10) && (d < 5) 我将变量与运算符分开并初始化我的上下文,但我不知道哪些是布尔值,哪些是整数。我尝试使用nullnew Object() 初始化上下文中的所有变量,但它没有按预期工作。请参阅下面的示例代码:

import java.util.HashMap;
import java.util.Map;

import org.mvel2.MVEL;

public class Test {

    private static Map<String, Object> context = new HashMap<String, Object>();

    public static void main(String[] args){

        String expression = "(a && b) && (c == 10) && (d < 5)";

        context.put("a", new Object());
        context.put("b", new Object());
        context.put("c", new Object());
        context.put("d", new Object());

        //do some processing and get the right value, replacing it in the context with the right type

        evaluate(expression,context); //just to try to evaluate with nothing set, crashes

        context.put("a", new Boolean(true));
        evaluate(expression,context);//crashes same as above

        context.put("b", new Boolean(true));
        evaluate(expression,context); //works. the expression is not yet true but it does not crash

        context.put("c", new Integer(10));
        context.put("d", new Integer(1));
        evaluate(expression,context); //works. expression is true

}

    private static void evaluate(String expression, Map<String,Object> context){
        if((Boolean)MVEL.eval(expression, context))
            System.out.println("Hooray");
        else
            System.out.println("Boo!"); 
    }

}

当它崩溃时,我收到这条消息:Exception in thread "main" org.mvel2.ScriptRuntimeException: expected Boolean; but found: java.lang.Object 如果我用null 初始化它会崩溃说..but found: null 我猜它在 MVEL.eval()方法它应该接收布尔值作为第一个变量,但我发现行为不一致。 第二个例子让我更加困惑。请参阅下面的示例代码:

import java.util.HashMap;
import java.util.Map;

import org.mvel2.MVEL;

public class Test {

    private static Map<String, Object> context = new HashMap<String, Object>();

    public static void main(String[] args){

        context.put("a", null);
        context.put("b", null);
        context.put("c", null);

        String expression = "( a > b + 2 ) && ( c < a - 5 )";

        evaluate(expression,context); //this time it does not crash. it evaluates correctly as false

         //do some processing and get the right value, and replace it in the context

        context.put("a",new Integer(25));
        evaluate(expression,context); //crashes. error below
        context.put("b", new Integer(20));
        context.put("c", new Integer(10));

        evaluate(expression,context); //evaluates correctly to true.
}

    private static void evaluate(String expression, Map<String,Object> context){
        if((Boolean)MVEL.eval(expression, context))
            System.out.println("Hooray");
        else
            System.out.println("Boo!"); 
    }

}

第二个示例中的崩溃错误消息是:Exception in thread "main" [Error: failed to subEval expression] [Near : {... ( a > b + 2 ) && ( c < a - 5 ) ....}] ^ 我的上下文变量是否可以默认初始化?我可以用new Boolean(false) 初始化它们,但这会影响表达式。我必须使用严格类型或强类型吗?顺便说一句,我没有找到任何像样的类文档..任何建议都值得赞赏。谢谢。

【问题讨论】:

  • 即使我使用 MVEl,并开发了自己的业务规则引擎,底层使用 MVEl 来评估表达式,我建议您强烈构建解析逻辑...意思是 (a + b), a and b 应该是number 仅限类型,a 不能为布尔值,本例为字符串。
  • Marius 您可能还需要维护运算符和支持的操作数数据类型等的映射。
  • 感谢您的回复。这就是我想要避免的,在那个级别创建一个“过于”复杂的解析函数并找出变量在哪里(运算符的左侧或右侧等)。我已经尽可能将运算符拆分为逻辑或算术。顺便说一句,是否有一些预定义的常量来保存这些运算符?如前所述,我找不到“体面”的文档。也许我在链接中迷路了,我想你比我有更多的经验。如果没有,我想到了一些解决方法。我会尝试它们,如果我想出一个干净/体面的解决方案,我会发布它。
  • 是的,我同意,你不会在网上找到太多,但我还是会强迫你使用一些解析逻辑,MVEL 不会像你想象的那样计算,如果表达式在 MVEL 方面是无效的,它会抛出异常。在从 MVEL 引发异常之后或在向 MVEL 发送表达式之前,您将在某个地方或另一个地方展示您的智能。
  • 呵呵呵呵.. 你不能强迫我:] 好吧,我确实设置了一些解析逻辑,因为无论如何你都需要,但我不希望在那个级别有那么多开销。我没有使用 Java 反编译器跟踪 MVEL.eval() 函数内部发生的所有事情,但我认为我可以在上下文中动态注入,此时我找出了该变量的数据类型。它不是基于我在 MVEL 库中找到的某些函数,而纯粹是你如何编程它......它会有点脏。不过,感谢您的建议,祝您好运。

标签: java mvel variable-types


【解决方案1】:

首先,您可以让 MVEL 自动获取输入变量。不幸的是,MVEL 没有告诉你它认为对象类型是什么。所以,例如:

Public class MvelVarTest {

public static void main(String[] args) {
    String expression = "( a > b + 2 ) && ( c < a - 5 )";
    ParserContext context = new ParserContext();
    Serializable compiledExpression = MVEL.compileExpression(expression, context);

    //Now the context will have a list of all the inputs.  Unfortunatly it does not tell you what type of Object the input is.
    for (Map.Entry<String,Class> entry : context.getInputs().entrySet()) {
        System.out.println("Variable name : "+entry.getKey()+", Data Type = "+entry.getValue().toString());
    }

    //Now, you can assign values to the data and run the expression.
    Map values = new HashMap();
    values.put("a",25);
    values.put("b",20);
    values.put("c",10);

    //And we can get a boolean answer
    System.out.println("Result of running formula with (a=25, b=20, c=10) = "+MVEL.executeExpression(compiledExpression,values,Boolean.class));
}

}

但是,当您使用您的值设置 HashMap 时,您可以只放入字符串值,而 MVEL 会“自动转换”它。

【讨论】:

  • 感谢您的回答,但恐怕这不是解决方案。您需要各种类型的变量,因为“自动转换”对于我需要评估的表达式来说是不够的。
猜你喜欢
  • 2018-05-13
  • 2021-07-23
  • 1970-01-01
  • 2015-03-23
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 2021-03-19
  • 1970-01-01
相关资源
最近更新 更多