all Jexl objects in scripts return null on any method call

195 views Asked by At

I'm trying to get a jexl script to work.

// arranging namespace Print
Map<String, Object> ns = new HashMap<>(1);
ns.put("Print", System.out); // make System.out.println available in expressions
JexlEngine je = new JexlBuilder().namespaces(ns).create();

// arranging custom Map for accessible variable 'agent' in script
Map<String, Object> myMap = ....;
myMap.put("agent", agentRef);
JexlContext jc = new MapContext(myMap);

// arranging script
JexlScript script = je.createScript(expression);
Object result = script.execute(jc);

with the expression being this:

{
   Print:println("blabla");
   const x = agent.getId();
   Print:println(x);
   return true;
}

The first command just prints "blabla" to the console, so the printing via System.out.println works flawless.

However, for the variable agent: it does exist, because jexl doesn't report "unsolvable variable". However, any method of the agent Object which I try to call, always returns null. I just get a null printed to the console. When I debug, the agentRef does have values other than null on its fields, just before I put it in the Map. So the fields are NOT null.

Also, when I call agent.id (which should be possible, it is just a POJO), I get "undefined property 'id', assuming false". Whereas agent.getId() returns just null.

Anyone any idea what could go wrong here?

I tried other syntaxes, but to no avail. I tried using jc.set("agent", agentRef), but same result.

2

There are 2 answers

0
henrib On

JEXL will only see/introspect public classes for which it is allowed to through permissions; your own classes/packages must be allowed (they aren't by default) and they must be public. To learn how to create proper permissions and to avoid using JexlPermissions.UNRESTRICTED in production, see JexlPermissions

0
Mo'in Creemers On

You need to use JexlPermissions.UNRESTRICTED:

JexlEngine jexl = new JexlBuilder().features(features)
                .permissions(JexlPermissions.UNRESTRICTED).create();

If you are using Java 17 or later, you need to 'expose' the object to the script as well. Your module should contain a module-info.java file. If the namespace of the class is 'com.foo' then the module-info.java file should contain something like this:

module <name of your module> {
    opens com.foo;
}

If you do not do this, Jexl will not be able to see the method using Reflection. No error is thrown.