Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Information Provided
-
3.2.1
-
None
-
Java 17; Windows 10
Description
In my Guise Mummy static site generator I'm using JEXL to interpret the built-in Mesh Expression Language (MEXL). Everything was working fine with JEXL 3.1. In fact the entire Guise Mummy web site itself was produced using Guise Mummy with MEXL on top of JEXL.
But when I upgrade to JEXL 3.2.1, the unit tests break. The MEX+JEXL error message says "Error in MEXL expression `foo.bar`: io.guise.mesh.JexlMexlEvaluator.evaluate:93 undefined property 'bar'", but if you look in the stack trace, you'll see that the problem seems to be a deeper NullPointerException which InterpreterBase.getAttribute(…) catches and effectively ignores, making it look like the problem was a missing variable.
} catch (final Exception xany) { xcause = xany; }
Here's the real problem:
Caused by: java.lang.NullPointerException: Cannot invoke "org.apache.commons.logging.Log.isDebugEnabled()" because "log" is null at org.apache.commons.jexl3.internal.introspection.ClassMap.populateWithClass(ClassMap.java:296) at org.apache.commons.jexl3.internal.introspection.ClassMap.populateWithInterface(ClassMap.java:270) at org.apache.commons.jexl3.internal.introspection.ClassMap.create(ClassMap.java:229) at org.apache.commons.jexl3.internal.introspection.ClassMap.<init>(ClassMap.java:100) at org.apache.commons.jexl3.internal.introspection.Introspector.getMap(Introspector.java:315) at org.apache.commons.jexl3.internal.introspection.Introspector.getMethod(Introspector.java:146) at org.apache.commons.jexl3.internal.introspection.Introspector.getMethod(Introspector.java:133) at org.apache.commons.jexl3.internal.introspection.PropertyGetExecutor.discoverGet(PropertyGetExecutor.java:107) at org.apache.commons.jexl3.internal.introspection.PropertyGetExecutor.discover(PropertyGetExecutor.java:42) at org.apache.commons.jexl3.internal.introspection.Uberspect.getPropertyGet(Uberspect.java:263) at org.apache.commons.jexl3.internal.InterpreterBase.getAttribute(InterpreterBase.java:971) at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:1108) at org.apache.commons.jexl3.parser.ASTIdentifierAccess.jjtAccept(ASTIdentifierAccess.java:104) at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:1156) at org.apache.commons.jexl3.parser.ASTReference.jjtAccept(ASTReference.java:19) at org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:1029) at org.apache.commons.jexl3.parser.ASTJexlScript.jjtAccept(ASTJexlScript.java:58) at org.apache.commons.jexl3.internal.Interpreter.interpret(Interpreter.java:193) at org.apache.commons.jexl3.internal.Script.execute(Script.java:188) at org.apache.commons.jexl3.internal.Script.evaluate(Script.java:180) ... 72 more
Here's the line in question inside ClassMap.populateWithClass(ClassMap cache, Permissions permissions, Class<?> clazz, Log log):
if (pmi != null && pmi != CACHE_MISS && log.isDebugEnabled() && !key.equals(new MethodKey(pmi))) {
For some reason your internal ClassMap class is being passed a Log that is null. Looking up the stack trace, it would appear this is coming from your Introspector. (There is a similar error on Stack Overflow with no answers; I don't know if they are using JAXL.)
- First, passing the Log around as a parameter is an antipattern. Logging is a cross-cutting concern; passing it around as a parameter is a bad idea.
- I wish you were using SLF4J like practically everyone else instead of org.apache.commons.logging.
- You shouldn't catch NullPointerException and turn it into a "normal" error condition, trying to say that a variable wasn't defined when really this was an internal error with the library.
In any case, for some reason JEXL 3.2.1 isn't initializing its internal logging support.
To reproduce this:
- Clone Guise Mummy 0.5.3.
- In the overall project pom.xml, change the version of org.apache.commons:commons-jexl3 from <version>3.1</version> to <version>3.2.1</version>.
- Run mvn clean verify.