[
https://issues.apache.org/jira/browse/JEXL-387?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17640291#comment-17640291
]
Garret Wilson commented on JEXL-387:
------------------------------------
[~ggregory], switching to the latest v3.3-SNAPSHOT stops the log-related
{{NullPointerException}}. Most of the unit tests pass now.
However a couple of other unit tests are now breaking. (Let me know if I should
file a separate ticket.) In the Mesh templating, we have an {{mx:each}}
attribute (similar to JSP or Thymeleaf) which loops through and replicates some
HTML element (e.g. an {{<li>}} inside an {{<ul>}}) for each value in a list. It
assigns each value, one at a time, to a variable {{it}} in the context. That is
working fine. But on each iteration it also assigns {{iter}} in the context,
with the value being an instance of
[{{MeshIterator}}|https://github.com/globalmentor/guise-mummy/blob/main/mesh/src/main/java/io/guise/mesh/MeshIterator.java].
That object has, among other things, {{getCurrent()}}:
{code:java}
/**
* Returns the current item. This will be the result of the last successful
call to {@link #next()}.
* @throws NoSuchElementException if iteration has not yet started.
* @return The current item.
*/
public Object getCurrent() { ... }
{code}
To make a long story short, the MEXL expression should be able to use
{{iter.current}} to get the value, but it's not finding it. I traced through
the new code, and it's finding the {{MeshIterator}} instance just fine and
assigning it to {{iter}}. The problem is that JEXL's {{ClassMap}} (probably
inside {{create()}}) is not finding and caching {{getCurrent()}} mapped to the
{{current}} property.
This worked fine in earlier versions. You can reproduce it exactly as explained
in the description, except using the {{-SNAPSHOT}} version you mentioned and
running the {{GuiseMeshTest.testMxEachWithIterVar()}}.
Did something change in the {{-SNAPSHOT}} version that would make it no longer
recognize a public {{getCurrent()}} method as representing a readable
{{current}} property?
> v3.2.1 breaks with logger-related NullPointerException
> ------------------------------------------------------
>
> Key: JEXL-387
> URL: https://issues.apache.org/jira/browse/JEXL-387
> Project: Commons JEXL
> Issue Type: Bug
> Environment: Java 17; Windows 10
> Reporter: Garret Wilson
> Priority: Major
>
> In my [Guise Mummy|https://github.com/globalmentor/guise-mummy] static site
> generator I'm using JEXL to interpret the built-in [Mesh Expression
> Language|https://github.com/globalmentor/guise-mummy/tree/main/mesh] (MEXL).
> Everything was working fine with JEXL 3.1. In fact the entire [Guise Mummy
> web site|https://guise.io/mummy/] 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.
> {code:java}
> } catch (final Exception xany) {
> xcause = xany;
> }
> {code}
> Here's the real problem:
> {noformat}
> 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
> {noformat}
> Here's the line in question inside {{ClassMap.populateWithClass(ClassMap
> cache, Permissions permissions, Class<?> clazz, Log log)}}:
> {code:java}
> if (pmi != null && pmi != CACHE_MISS && log.isDebugEnabled() &&
> !key.equals(new MethodKey(pmi))) {
> {code}
> 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|https://stackoverflow.com/q/64927054] 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|https://github.com/globalmentor/guise-mummy/releases/tag/v0.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}}.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)