Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
3.1
-
None
Description
JEXL makes some nice diagnostic messages available from Exception.getMessage(). However, in the case where a JexlException.Parsing is thrown in the middle of a long expression, getMessage() throws a StringIndexOutOfBoundsException instead of returning a nice diagnostic message.
I encountered this in JEXL 3.1, but have confirmed that it is reproducible using a recent clone of the GitHub repository.
Impact:
In the case where the JEXL programmer includes the badly-formed expression, my program, which uses JEXL, throws an unhanded exception, instead of printing out a clear message to the JEXL programmer.
Steps to Reproduce:
@Test public void testLongParseError() throws IOException { JexlEngine jexl = new JexlBuilder().create(); // Extended form of: 'literal' + VARIABLE 'literal' // missing + operator here ---------------^ String longExpression = "" + // "'THIS IS A VERY VERY VERY VERY VERY VERY VERY " + // "VERY VERY LONG STRING CONCATENATION ' + VARIABLE ' <--- " + // "error: missing + between VARIABLE and literal'"; try { jexl.createExpression(longExpression); Assert.fail("parsing malformed expression did not throw exception"); } catch (JexlException.Parsing exception) { Assert.assertEquals("???", exception.getMessage()); } }
What Happens:
createExpression() throws a JexlException.Parsing, as expected.
Calling getMessage() on the resulting JexlException.Parsing, in turn, throws StringIndexOutOfBoundsException.
Expected Result:
getMessage() returns a brief description of the syntax error.
Technical Details:
The problem might be in JexlException.parseError. In the case where the expression is long (in this case, the part after the VARIABLE), it tries to extract a snippet of the error.
protected String parserError(String prefix, String expr) { int length = expr.length(); if (length < MAX_EXCHARLOC) { return prefix + " error in '" + expr + "'"; } else { int begin = info.getColumn(); // <---- column in original expression, not within expr // In this case, begin > length int end = begin + (MAX_EXCHARLOC / 2); begin -= (MAX_EXCHARLOC / 2); if (begin < 0) { end -= begin; begin = 0; } return prefix + " error near '... " + expr.substring(begin, end > length ? length : end) + " ...'"; } }
However, the expression that it's given is already an extract, not the entire line:
' <--- error: missing + between VARIABLE and literal'
info.getColumn() returns an index in the original expression, which is already already past the end of the expr. So when JexlException.parseError invokes expr.substring(), it throws StringIndexOutOfBoundsException.