简体   繁体   中英

creating context for MVEL with different variable types

I am using MVEL to evaluate arithmetic and logical expressions or a combination of the two. The thing is that I do not know beforehand all the variable types, without creating a pretty complex parsing method for the expression itself (which is passed via a settings file). I know their type only when I go through my data and update the context. For instance, consider the expression (a && b) && (c == 10) && (d < 5) I separate the variables from the operators and initialize my context, but I do not know which are booleans and which are integers. I have tried to initialize all variables in the context with null or new Object() but it does not work as expected. See example code below:

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!"); 
    }

}

when it crashes, I get this message: Exception in thread "main" org.mvel2.ScriptRuntimeException: expected Boolean; but found: java.lang.Object Exception in thread "main" org.mvel2.ScriptRuntimeException: expected Boolean; but found: java.lang.Object If I initialize with null it would crash saying ..but found: null My guess is that it figures out in the MVEL.eval() method it should receive booleans as the first variables, but I do not find the behavior consistent. A second example makes me even more confused. See example code below:

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!"); 
    }

}

The error message for the crash in this second example is: Exception in thread "main" [Error: failed to subEval expression] [Near : {... ( a > b + 2 ) && ( c < a - 5 ) ....}] ^ Isn't there a default initialization of my context variables possible? I can initialize them with new Boolean(false) but that can influence the expression. Do I have to use some Strict Typing or Strong Typing? BTW, I do not find any decent documentation of the classes.. any suggestions are appreciated. Thank you.

First of all, you can Ask MVEL to get you the input variables automatically. Unfortunately, MVEL does not tell you what it thinks the object type is. So, for instance:

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));
}

}

However, when you set up the HashMap with your values, you could of just put string values in, and MVEL would of "auto converted" it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM