Mvel evaluation

Ankur Singhal picture Ankur Singhal · Jun 16, 2014 · Viewed 9.3k times · Source

Problem Statement: Say I have a expression (a + b + c), and I want to calculate its value and assign to some variable. Later I want use that variable value in some other logic. This is all done through MVEL. Issue is if anyone out of (a,b,c) is null, MVEL evaluates in a string format.

So to avoid this, I created my own function to pass each object and if it is null, make it zero.

Sample code below

public class MvelTest {

    public static void main(String[] args) {

        Map map = new HashMap();

        VariableResolverFactory functionFactory = new MapVariableResolverFactory(map);
        MVEL.eval("checkNullValue = def (x) { x == null ? 0 : x };", functionFactory);

        map.put("a", null);
        map.put("b", 1);
        map.put("c", 1);

        Serializable str = MVEL.compileExpression("( ( checkNullValue(a) + checkNullValue(b) + checkNullValue(c) ) > 2 ) ? d=2 : d=3");

        MVEL.executeExpression(str, map, functionFactory);
        System.out.println(map);
        System.out.println(map.get("d"));
    }
}

Output

{checkNullValue=function_prototype:null, b=1, c=1, a=null}
null

I am not able to get value of "d" here, and if I remove factory and null check function it behaves and I am able to get the value of "d". But I have to make it null safe for arithmetic operation, Since MVEL cannot handle this.

Also (null * 23), MVEL returns as false.

Answer

tobias_k picture tobias_k · Jun 16, 2014

The problem is with your ternary operator. I am not sure how MVEL evaluates those (the way you use them would be illegal in Java), but it seems like putting the assignment in the then/else part does not work... or rather, it (for whatever reason) does work for the 'then' part (before :) but fails for the 'else' part (after :).

So if the sum is > 2 it works, whether or not you are using the null-check function, and otherwise it fails.

You should fix your expression and put the assignment in front of the ternary operator:

MVEL.compileExpression("d = cnv(a) + cnv(b) + cnv(c) > 2 ? 2 : 3")

Update: Generally, this is what I observed, independently of a, b, c, and cnv:

MVEL.compileExpression("true  ? d=1 : d=2"); // d ends up as 1
MVEL.compileExpression("false ? d=1 : d=2"); // d is null / unknown
MVEL.compileExpression("d = guard ? 1 : 2"); // always works