2

I am trying to implement a custom class that should behave like Boolean in Jexl expressions:

Example: Object result = jexl.createExpression("a || b").evaluate(context)

Where aand b are instances of a custom class that contains an boolean and extra information that should be carried through the evaluated expresssion so that it can be accessed in the end in result.

I have read that Jexl3 should support operator overloading and it seems to have all the necessary structures for defining own operators for custom classes - however I am unable to understand what steps are necessary for doing so.

I already tries to extend Uberspect and JexlArithmetic by custom implementations, however I only found out that using toBoolean I can convert my custom objects to Boolean (which makes result a Boolean - hence I loose all the extra information).

How to use/extend Jexl properly to provide boolean operators for custom classes?

JMax
  • 1,134
  • 1
  • 11
  • 20

2 Answers2

3

Just extend JexlArithmetic class and override or method inside.

public class ExtendedJexlArithmetic extends JexlArithmetic
{
    public Object or(YourCustomClass left, YourCustomClass right)
    {
            return left.or(right); // make sure you've implemented 'or' method inside your class
    }
}

And then try below:

JexlContext jexlContext = new MapContext();

jexlContext.set("a", new YourCustomClass());
jexlContext.set("b", new YourCustomClass());

JexlEngine jexlEngine=new JexlBuilder().arithmetic(new ExtendedJexlArithmetic (true)).create();

System.out.println(jexlEngine.createScript("a | b").execute(jexlContext);
Pratik
  • 908
  • 2
  • 11
  • 34
  • It took me some time to figure out why this example works and mine not. Your solution the the workaround to implement the boolean logic in the bitwise operator. Therefore you are evaluating `a | b` instead of `a || b` as we would normally write it in Java. This is a workaround which only works unless you require bitwise operations in your jexl code. And of course it is totally forbidden to use the boolean operators `||` and `&&`! – JMax Apr 18 '18 at 12:23
  • @JMax Yes, you can use '|' but not '||', as '||' is not a valid operator in JEXL. – Pratik Apr 19 '18 at 04:49
  • Unfortunately I have to say that your approach looks nice, but in the end it does not work, simply because one essential boolean operation is missing: `not` or `!`. There I stongly recommend to everybody not to follow this approach :( – JMax May 18 '18 at 09:35
  • @JMax It does have - or negate(x) for negation. See here: https://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/package-summary.html – Pratik May 24 '18 at 05:51
  • Jexl has, but it does not work in combination with your workaround to use `|` instead of `||`. If you use `not` Jexl converts the object internally to a `boolean` and all the extra information is gone - which exactly the default behavior and why I created this question. Conclusion: JEX is simply not usable for that sceanrio IT DOES NOT WORK! – JMax May 25 '18 at 11:51
  • @JMax You are confusing. What is the exact use case, you are trying to achieve? The example is only for reference, how to extend operators. Are you looking for specific use case or operator ? Please explain in detail so that we can help you. – Pratik May 31 '18 at 02:46
1

You are on the right path, you need to extend JexlArithmetic and implement your overloads. The various overloadable operators are described in http://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/JexlOperator.html . There is a test/example in http://svn.apache.org/viewvc/commons/proper/jexl/tags/COMMONS_JEXL_3_1/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java?view=markup#l666 .

henrib
  • 187
  • 6
  • 1
    Thanks for the info. However it seems like boolean logic like `||` and `&&` is not covered by the `Arithmetic` implementation. Operator overloading only works for numbers, not boolean logic. And I can't add new operators as `JexlOperator` is an Enum which can't be subclassed. – JMax Sep 25 '17 at 19:45
  • You are correct, my bad for overlooking the '||'; unfortunately, the short-circuit operators can not be overloaded at this stage, the lazy second argument evaluation complicating implementation & signature quite a lot. Workaround would be to use / overload '|' and '&'. – henrib Sep 26 '17 at 09:22