Is it possible to define some custom precompiled function with MVEL and use one in another compiled expressions? If I try the following:
MVEL.compileExpression("function hello() { System.out.println(\"Hello!\"); hello(); return x * y;");
I get Exception in thread "main" [Error: duplicate function: hello]
when try to execure it second time.
It looks like I should declare the function not at the expression itself, but some kind of context. I played with ParsedContext for a while, but always got Exception in thread "main" [Error: unable to access property (null parent): hello]
.
Internet is full of tutorials that cover different MVEL language usage topics, but such embedding topics a very poorly documented. Could you please give me some clue what I'm doing wrong?
P.S. I don't want to execute some function from Java. I need to define them dynamically with MVEL.
This is a bit trickier than some common use-cases, although it is possible.
Fundamentally, what you need to do is create a script which defines your functions, like so:
VariableResolverFactory functionFactory = new MapVariableResolverFactory();
MVEL.eval("def foo() { System.out.println("foo"); }; def bar() { System.out.println("bar") };", functionFactory);
Then, what you do is back-chain this factory to any expression you run:
VariableResolverFactory myVarFactory = new MapVariableResolverFactory();
myVarFactory.setNextFactory(functionFactory);
Serializable s = MVEL.compileExpression("foo(); bar();");
MVEL.executeExpression(s, myVarFactory);
Functions are recorded as references on the variable table, so you can use regular variable factory back-chaining to share them in MVEL.
Note: You shouldn't re-share 'myVarFactory'. You want to create a new one every time. You only want to recycle 'functionFactory' and back-chain it to the per-run factories as shown above. Otherwise you'll end up sharing local var state between executions -- and that's not thread-safe