This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git


The following commit(s) were added to refs/heads/master by this push:
     new ef8a3e3  JEXL-323, JEXL-327: fixed error reporting an null checks Task 
#JEXL-327 - map[null] does not work in assignment context
ef8a3e3 is described below

commit ef8a3e3435e2948b2afd7972901eac5a45721b19
Author: henrib <[email protected]>
AuthorDate: Wed Jan 29 17:57:01 2020 +0100

    JEXL-323, JEXL-327: fixed error reporting an null checks
    Task #JEXL-327 - map[null] does not work in assignment context
---
 RELEASE-NOTES.txt                                  |   3 +
 .../apache/commons/jexl3/internal/Interpreter.java |  29 +++---
 .../org/apache/commons/jexl3/parser/JexlNode.java  |   5 +-
 src/site/xdoc/changes.xml                          |   9 ++
 .../org/apache/commons/jexl3/Issues300Test.java    | 112 +++++++++++++++++----
 5 files changed, 122 insertions(+), 36 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index c329e77..27f7655 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -74,8 +74,11 @@ New Features in 3.2:
 
 Bugs Fixed in 3.2:
 ==================
+* JEXL-327:      map[null] does not work in assignment context
+* JEXL-326:      Link to "JavaCC" on syntax reference page is broken
 * JEXL-325:      Potential race-condition in NumberParser.toString()
 * JEXL-324:      JexlEngine.createExpression("new()").getParsedText() throws 
NPE
+* JEXL-323:      Ant-style variables can throw exception when evaluated for 
their value
 * JEXL-322:      JXLT String literals cannot contain curly brace
 * JEXL-321:      Empty do-while loop is broken
 * JEXL-320:      "mvn test" fails with COMPILATION ERROR in 
SynchronizedArithmetic.java on Java 11
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java 
b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
index d0dd721..99a81c9 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -1132,6 +1132,7 @@ public class Interpreter extends InterpreterBase {
         for (int c = 0; c < numChildren; c++) {
             objectNode = node.jjtGetChild(c);
             if (objectNode instanceof ASTMethodNode) {
+                antish = false;
                 if (object == null) {
                     // we may be performing a method call on an antish var
                     if (ant != null) {
@@ -1147,19 +1148,17 @@ public class Interpreter extends InterpreterBase {
                             } else {
                                 // remove method name from antish
                                 ant.delete(alen, ant.length());
+                                ptyNode = objectNode;
                             }
                         }
                     }
                     break;
-                } else {
-                    antish = false;
                 }
             } else if (objectNode instanceof ASTArrayAccess) {
+                antish = false;
                 if (object == null) {
                     ptyNode = objectNode;
                     break;
-                } else {
-                    antish = false;
                 }
             }
             // attempt to evaluate the property within the object 
(visit(ASTIdentifierAccess node))
@@ -1216,7 +1215,7 @@ public class Interpreter extends InterpreterBase {
                 break; //
             }
         }
-        // am I the left-hand side of a safe op ?
+        // dealing with null
         if (object == null) {
             if (ptyNode != null) {
                 if (ptyNode.isSafeLhs(isSafe())) {
@@ -1224,19 +1223,23 @@ public class Interpreter extends InterpreterBase {
                 }
                 if (ant != null) {
                     String aname = ant.toString();
-                    boolean undefined = !(context.has(aname) || 
isLocalVariable(node, 0) || isFunctionCall(node));
+                    boolean undefined = !(context.has(aname));
                     return unsolvableVariable(node, aname, undefined);
                 }
-                return unsolvableProperty(node, stringifyProperty(ptyNode), 
ptyNode == objectNode, null);
+                return unsolvableProperty(node,
+                        stringifyProperty(ptyNode), ptyNode == objectNode, 
null);
             }
             if (antish) {
                 if (node.isSafeLhs(isSafe())) {
                     return null;
                 }
                 String aname = ant != null ? ant.toString() : "?";
-                boolean undefined = !(context.has(aname) || 
isLocalVariable(node, 0) || isFunctionCall(node));
-                if (undefined || arithmetic.isStrict()) {
-                    return unsolvableVariable(node, aname, undefined);
+                boolean defined = context.has(aname);
+                if (defined && !arithmetic.isStrict()) {
+                    return null;
+                }
+                if (!defined || !(node.jjtGetParent() instanceof 
ASTJexlScript)) {
+                    return unsolvableVariable(node, aname, !defined);
                 }
             }
         }
@@ -1450,10 +1453,8 @@ public class Interpreter extends InterpreterBase {
         } else {
             throw new JexlException(objectNode, "illegal assignment form");
         }
-        if (property == null) {
-            // no property, we fail
-            return unsolvableProperty(propertyNode, "<?>.<null>", true, null);
-        }
+        // we may have a null property as in map[null], no check needed.
+        // we can not *have* a null object though.
         if (object == null) {
             // no object, we fail
             return unsolvableProperty(objectNode, "<null>.<?>", true, null);
diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java 
b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
index 940f17a..f085182 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
@@ -260,7 +260,10 @@ public abstract class JexlNode extends SimpleNode {
         JexlNode node = this;
         for (JexlNode walk = node.jjtGetParent(); walk != null; walk = 
walk.jjtGetParent()) {
             // protect only the condition part of the ternary
-            if (walk instanceof ASTTernaryNode || walk instanceof ASTNullpNode 
|| walk instanceof ASTEQNode || walk instanceof ASTNENode) {
+            if (walk instanceof ASTTernaryNode
+                || walk instanceof ASTNullpNode
+                || walk instanceof ASTEQNode
+                || walk instanceof ASTNENode) {
                 return node == walk.jjtGetChild(0);
             }
             if (!(walk instanceof ASTReference || walk instanceof 
ASTArrayAccess)) {
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 01e461a..8d80239 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -26,12 +26,21 @@
     </properties>
     <body>
         <release version="3.2" date="unreleased">
+            <action dev="henrib" type="fix" issue="JEXL-327" due-to="David 
Costanzo">
+                map[null] does not work in assignment context
+            </action>
+            <action dev="henrib" type="fix" issue="JEXL-326" due-to="David 
Costanzo">
+                Link to "JavaCC" on syntax reference page is broken
+            </action>
             <action dev="Dmitri Blinov" type="fix" issue="JEXL-325" 
due-to="Dmitri Blinov">
                 Potential race-condition in NumberParser.toString()
             </action>
             <action dev="henrib" type="fix" issue="JEXL-324" due-to="David 
Costanzo">
                 JexlEngine.createExpression("new()").getParsedText() throws NPE
             </action>
+            <action dev="henrib" type="fix" issue="JEXL-323" due-to="David 
Costanzo">
+                Ant-style variables can throw exception when evaluated for 
their value
+            </action>
             <action dev="henrib" type="fix" issue="JEXL-322" 
due-to="Constantin Hirsch">
                 JXLT String literals cannot contain curly braces
             </action>
diff --git a/src/test/java/org/apache/commons/jexl3/Issues300Test.java 
b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
index f4c260f..65a4d6a 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues300Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
@@ -18,6 +18,7 @@ package org.apache.commons.jexl3;
 
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -25,7 +26,6 @@ import java.util.List;
 import java.util.Map;
 import org.junit.Assert;
 import static org.junit.Assert.assertEquals;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -47,7 +47,7 @@ public class Issues300Test {
                     Assert.fail(src + ": Should have failed");
                 }
             } catch (Exception ex) {
-                //
+                Assert.assertTrue(ex.getMessage().contains("x"));
             }
         }
     }
@@ -421,26 +421,68 @@ public class Issues300Test {
         Assert.assertEquals("L'utilisateur user322 s'est connecte", output);
     }
     
-    @Ignore
+    @Test
     public void test323() throws Exception {
-        // Create or retrieve an engine
         JexlEngine jexl = new JexlBuilder().safe(false).create();
-        // on recent code: JexlEngine jexl = new 
JexlBuilder().safe(false).create();
-
-        // Populate to identical global variables
-        JexlContext jc = new MapContext();
-        jc.set("NormalVariable", null);
-        jc.set("ant.variable", null);
-
-        // Evaluate the value of the normal variable
-        JexlExpression expression1 = jexl.createExpression("NormalVariable");
-        Object o1 = expression1.evaluate(jc);
-        Assert.assertEquals(null, o1);
-
-        // Evaluate the value of the ant-style variable
-        JexlExpression expression2 = jexl.createExpression("ant.variable");
-        Object o2 = expression2.evaluate(jc); // <-- BUG: throws exception 
instead of returning null
-        Assert.assertEquals(null, o2);
+        Map<String,Object> vars = new HashMap<String, Object>();
+        JexlContext jc = new MapContext(vars);
+        JexlScript script;
+        Object result;
+        
+        // nothing in context, ex
+        try {
+         script = jexl.createScript("a.n.t.variable");
+         result = script.execute(jc); 
+         Assert.fail("a.n.t.variable is undefined!");
+        } catch(JexlException.Variable xvar) {
+            Assert.assertTrue(xvar.toString().contains("a.n.t"));
+        }
+        
+        // defined and null
+        jc.set("a.n.t.variable", null);
+        script = jexl.createScript("a.n.t.variable");
+        result = script.execute(jc); 
+        Assert.assertEquals(null, result);
+        
+        // defined and null, dereference
+        jc.set("a.n.t", null);
+        try {
+         script = jexl.createScript("a.n.t[0].variable");
+         result = script.execute(jc); 
+         Assert.fail("a.n.t is null!");
+        } catch(JexlException.Variable xvar) {
+            Assert.assertTrue(xvar.toString().contains("a.n.t"));
+        }
+        
+        // undefined, dereference
+        vars.remove("a.n.t");
+        try {
+         script = jexl.createScript("a.n.t[0].variable");
+         result = script.execute(jc); 
+         Assert.fail("a.n.t is undefined!");
+        } catch(JexlException.Variable xvar) {
+            Assert.assertTrue(xvar.toString().contains("a.n.t"));
+        }
+        // defined, derefence undefined property
+        List<Object> inner = new ArrayList<Object>();
+        vars.put("a.n.t", inner);
+        try {
+            script = jexl.createScript("a.n.t[0].variable");
+            result = script.execute(jc); 
+            Assert.fail("a.n.t is null!");
+        } catch(JexlException.Property xprop) {
+            Assert.assertTrue(xprop.toString().contains("0"));
+        }
+        // defined, derefence undefined property
+        inner.add(42);
+        try {
+            script = jexl.createScript("a.n.t[0].variable");
+            result = script.execute(jc); 
+            Assert.fail("a.n.t is null!");
+        } catch(JexlException.Property xprop) {
+            Assert.assertTrue(xprop.toString().contains("variable"));
+        }
+        
     }
     
     @Test
@@ -458,5 +500,33 @@ public class Issues300Test {
             Assert.assertTrue(xparse.toString().contains("new"));
         }
     }
-    
+
+    @Test
+    public void test325() throws Exception {
+        JexlEngine jexl = new JexlBuilder().safe(false).create();
+        Map<String, Object> map = new HashMap<String, Object>() {
+            @Override
+            public Object get(Object key) {
+                return super.get(key == null ? "" : key);
+            }
+
+            @Override
+            public Object put(String key, Object value) {
+                return super.put(key == null ? "" : key, value);
+            }
+        };
+        map.put("42", 42);
+        JexlContext jc = new MapContext();
+        JexlScript script;
+        Object result;
+
+        script = jexl.createScript("map[null] = 42", "map");
+        result = script.execute(jc, map);
+        Assert.assertEquals(42, result);
+        script = jexl.createScript("map[key]", "map", "key");
+        result = script.execute(jc, map, null);
+        Assert.assertEquals(42, result);
+        result = script.execute(jc, map, "42");
+        Assert.assertEquals(42, result);
+    }
 }

Reply via email to