Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
3.0
-
None
Description
I'm chasing strange bug where regardless of the JexlContext operating in non-strict mode the ArrayIndexOutOfBoundsException is thrown in the script like this
entity = args[0]; @lenient {copy = args[1]; xwsp = args[2]}
here is the stack trace
Caused by: java.lang.ArrayIndexOutOfBoundsException
at java.lang.reflect.Array.get(Native Method)
at org.apache.commons.jexl3.internal.introspection.ListGetExecutor.tryInvoke(ListGetExecutor.java:88)
at org.apache.commons.jexl3.internal.Interpreter.getAttribute(Interpreter.java:1700)
at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:945)
at org.apache.commons.jexl3.parser.ASTArrayAccess.jjtAccept(ASTArrayAccess.java:18)
at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:1013)
at org.apache.commons.jexl3.parser.ASTReference.jjtAccept(ASTReference.java:18)
at org.apache.commons.jexl3.internal.Interpreter.executeAssign(Interpreter.java:1119)
at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:1062)
at org.apache.commons.jexl3.parser.ASTAssignment.jjtAccept(ASTAssignment.java:18)
at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:578)
at org.apache.commons.jexl3.parser.ASTBlock.jjtAccept(ASTBlock.java:18)
at org.apache.commons.jexl3.internal.Interpreter.processAnnotation(Interpreter.java:1848)
at org.apache.commons.jexl3.internal.Interpreter$1.call(Interpreter.java:1856)
Unfortunately I haven't managed to create and provide reproducible test case, but from looking into the code I think the problem fires when the Interpreter tries to call cached method ListGetExecutor.tryInvoke() but does not catch subsequent exception.
I rewrote the code as follows and the problem seemed to go away
... Exception xcause = null; // attempt to reuse last executor cached in volatile JexlNode.value if (node != null && cache) { Object cached = node.jjtGetValue(); if (cached instanceof JexlPropertyGet) { JexlPropertyGet vg = (JexlPropertyGet) cached; try { Object value = vg.tryInvoke(object, attribute); if (!vg.tryFailed(value)) { return value; } } catch (Exception xany) { xcause = xany; } } } if (xcause == null) { // resolve that property List<PropertyResolver> resolvers = uberspect.getResolvers(operator, object); JexlPropertyGet vg = uberspect.getPropertyGet(resolvers, object, attribute); if (vg != null) { try { Object value = vg.invoke(object); // cache executor in volatile JexlNode.value if (node != null && cache && vg.isCacheable()) { node.jjtSetValue(vg); } return value; } catch (Exception xany) { xcause = xany; } } } ...