Java – Mvel evaluation

drools, java, mvel

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.

Best Solution

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 1MVEL.compileExpression("false ? d=1 : d=2"); // d is null / unknownMVEL.compileExpression("d = guard ? 1 : 2"); // always works