You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2020/08/30 14:45:03 UTC

[commons-jexl] branch master updated: JEXL-333: fixed namespace resolution on static only (private ctor) classes Task #JEXL-333 - Allow declaration of namespace within script

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 89a8d63  JEXL-333: fixed namespace resolution on static only (private ctor) classes Task #JEXL-333 - Allow declaration of namespace within script
89a8d63 is described below

commit 89a8d635a946edc111c7e57c18009ffc0ccdae6d
Author: henrib <he...@apache.org>
AuthorDate: Sun Aug 30 16:44:29 2020 +0200

    JEXL-333: fixed namespace resolution on static only (private ctor) classes
    Task #JEXL-333 - Allow declaration of namespace within script
---
 .../java/org/apache/commons/jexl3/JexlOptions.java |  2 +-
 .../org/apache/commons/jexl3/internal/Engine.java  |  8 ++-
 .../commons/jexl3/internal/InterpreterBase.java    | 28 +++++++-
 .../java/org/apache/commons/jexl3/PragmaTest.java  | 84 ++++++++++++++++++++++
 4 files changed, 118 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlOptions.java b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
index 78e274c..e54985e 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlOptions.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
@@ -40,7 +40,7 @@ import org.apache.commons.jexl3.internal.Engine;
  * @since 3.2
  */
 public final class JexlOptions {
-    /** The shared isntance bit. */
+    /** The shared instance bit. */
     private static final int SHARED = 7;
     /** The local shade bit. */
     private static final int SHADE = 6;
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
index ec8484f..ec2e58b 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -398,11 +398,15 @@ public class Engine extends JexlEngine {
                         // jexl.namespace.***
                         String nsname = key.substring(PRAGMA_JEXLNS.length());
                         if (nsname != null && !nsname.isEmpty()) {
-                            String nsclass = value.toString();
                             if (ns == null) {
                                 ns = new HashMap<>(functions);
                             }
-                            ns.put(nsname, nsclass);
+                            String nsclass = value.toString();
+                            try {
+                                ns.put(nsname, uberspect.getClassLoader().loadClass(nsclass));
+                            } catch (ClassNotFoundException e) {
+                                ns.put(nsname, nsclass);
+                            }
                         }
                     }
                 }
diff --git a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
index b56245a..557ca19 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
@@ -200,6 +200,7 @@ public abstract class InterpreterBase extends ParserVisitor {
                     }
                 }
                 if (functor == null) {
+                    // find a ctor with that context class
                     JexlMethod ctor = uberspect.getConstructor(namespace, context);
                     if (ctor != null) {
                         try {
@@ -211,13 +212,38 @@ public abstract class InterpreterBase extends ParserVisitor {
                             throw new JexlException(node, "unable to instantiate namespace " + prefix, xinst);
                         }
                     }
+                    // find a ctor with no arg
+                    if (functor == null) {
+                        ctor = uberspect.getConstructor(namespace);
+                        if (ctor != null) {
+                            try {
+                                functor = ctor.invoke(namespace);
+                            } catch (Exception xinst) {
+                                throw new JexlException(node, "unable to instantiate namespace " + prefix, xinst);
+                            }
+                        }
+                        // use a class, namespace of static methods
+                        if (functor == null) {
+                            // try to find a class with that name
+                            if (namespace instanceof String) {
+                                try {
+                                    functor = uberspect.getClassLoader().loadClass((String) namespace);
+                                } catch (ClassNotFoundException xignore) {
+                                    // not a class
+                                    namespace = null;
+                                }
+                            } else { // we know its a class
+                                functor = (Class<?>) namespace;
+                            }
+                        }
+                    }
                 }
             }
             // got a functor, store it and return it
             if (functor != null) {
                 synchronized (this) {
                     if (functors == null) {
-                        functors = new HashMap<String, Object>();
+                        functors = new HashMap<>();
                     }
                     functors.put(prefix, functor);
                 }
diff --git a/src/test/java/org/apache/commons/jexl3/PragmaTest.java b/src/test/java/org/apache/commons/jexl3/PragmaTest.java
index 713acf7..03a8bd2 100644
--- a/src/test/java/org/apache/commons/jexl3/PragmaTest.java
+++ b/src/test/java/org/apache/commons/jexl3/PragmaTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.jexl3;
 
+import java.util.Collections;
 import java.util.Map;
 import org.junit.Assert;
 import org.junit.Test;
@@ -77,6 +78,14 @@ public class PragmaTest extends JexlTestCase {
                 }
             }
         }
+
+        public void sleep(long ms) {
+            try {
+                Thread.sleep(ms);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
     }
 
     @Test
@@ -98,4 +107,79 @@ public class PragmaTest extends JexlTestCase {
             // ok, expected
         }
     }
+
+        
+    public static class StaticSleeper {
+        // precludes instantiation
+        private StaticSleeper() {}
+        
+        public static void sleep(long ms) {
+            try {
+                Thread.sleep(ms);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+    }
+    
+    public static class Sleeper {
+        public void sleep(long ms) {
+            try {
+                Thread.sleep(ms);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+    }
+
+    @Test
+    @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
+    public void testStaticNamespacePragma() throws Exception {
+        SafeContext jc = new SafeContext();
+        JexlScript script = JEXL.createScript(
+                "#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n"
+                + "sleeper:sleep(100);"
+                + "42");
+        Object result = script.execute(jc);
+        Assert.assertEquals(42, result);
+    }
+
+    @Test
+    @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
+    public void testStatictNamespacePragmaCtl() throws Exception {
+        Map<String, Object> ns = Collections.singletonMap("sleeper", StaticSleeper.class.getName());
+        JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
+        SafeContext jc = new SafeContext();
+        JexlScript script = jexl.createScript(
+                "sleeper:sleep(100);"
+                + "42");
+        Object result = script.execute(jc);
+        Assert.assertEquals(42, result);
+    }
+
+    @Test
+    @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
+    public void testNamespacePragma() throws Exception {
+        SafeContext jc = new SafeContext();
+        JexlScript script = JEXL.createScript(
+                "#pragma jexl.namespace.sleeper " + Sleeper.class.getName() + "\n"
+                + "sleeper:sleep(100);"
+                + "42");
+        Object result = script.execute(jc);
+        Assert.assertEquals(42, result);
+    }
+
+    @Test
+    @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
+    public void testNamespacePragmaCtl() throws Exception {
+        Map<String, Object> ns = Collections.singletonMap("sleeper", Sleeper.class.getName());
+        JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
+        SafeContext jc = new SafeContext();
+        JexlScript script = jexl.createScript(
+                "sleeper:sleep(100);"
+                + "42");
+        Object result = script.execute(jc);
+        Assert.assertEquals(42, result);
+    }
+
 }