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 2026/06/19 17:06:42 UTC

(commons-jexl) branch master updated: JEXL : release notes; - fixing unsafe JSR233 configuration;

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 1d41aecf JEXL : release notes; - fixing unsafe JSR233 configuration;
1d41aecf is described below

commit 1d41aecf9eaba2f0d6f3f9a7909aa886c00cfc0f
Author: Henrib <hb...@gmail.com>
AuthorDate: Fri Jun 19 19:06:33 2026 +0200

    JEXL : release notes;
    - fixing unsafe JSR233 configuration;
---
 .../commons/jexl3/scripting/JexlScriptEngine.java  |  62 +++++------
 .../jexl3/scripting/JexlScriptEngineFactory.java   |  61 ++++++++++-
 src/site/xdoc/relnotes.xml                         | 116 +++++++++++++++++++--
 .../jexl3/scripting/JexlScriptEngineTest.java      |  10 +-
 4 files changed, 199 insertions(+), 50 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java b/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
index 652d3419..3d9bb458 100644
--- a/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
+++ b/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
@@ -36,7 +36,6 @@ import javax.script.ScriptEngineFactory;
 import javax.script.ScriptException;
 import javax.script.SimpleBindings;
 
-import org.apache.commons.jexl3.JexlBuilder;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.JexlEngine;
 import org.apache.commons.jexl3.JexlException;
@@ -265,12 +264,7 @@ public class JexlScriptEngine extends AbstractScriptEngine implements Compilable
      * The shared engine instance.
      * <p>A single soft-reference JEXL engine and JexlUberspect is shared by all instances of JexlScriptEngine.</p>
      */
-    private static Reference<JexlEngine> ENGINE;
-
-    /**
-     * The permissions used to create the script engine.
-     */
-    private static JexlPermissions PERMISSIONS;
+    private static Reference<JexlEngine> engineReference;
 
     /** The logger. */
     static final Log LOG = LogFactory.getLog(JexlScriptEngine.class);
@@ -284,27 +278,26 @@ public class JexlScriptEngine extends AbstractScriptEngine implements Compilable
     /** Reserved key for JexlScriptObject. */
     public static final String JEXL_OBJECT_KEY = "JEXL";
 
+    /** Reserved key for script. */
+    private static final String SCRIPT = "script";
+
     /**
      * @return the shared JexlEngine instance, create it if necessary
      */
-    private static JexlEngine getEngine() {
-        JexlEngine engine = ENGINE != null ? ENGINE.get() : null;
+    private static JexlEngine getEngine(ScriptEngineFactory scriptEngineFactory) {
+        Reference<JexlEngine> ref = engineReference;
+        JexlEngine engine = ref != null ? ref.get() : null;
         if (engine == null) {
             synchronized (JexlScriptEngineFactory.class) {
-                engine = ENGINE != null ? ENGINE.get() : null;
+                ref = engineReference;
+                engine = ref != null ? ref.get() : null;
                 if (engine == null) {
-                    final JexlBuilder builder = new JexlBuilder()
-                            .strict(true)
-                            .safe(false)
-                            .logger(JexlScriptEngine.LOG)
-                            .cache(JexlScriptEngine.CACHE_SIZE);
-                    // ensure the script object class is always allowed for all permissions set
-                    JexlPermissions permissions = new JexlPermissions.ClassPermissions(
-                        PERMISSIONS == null ? JexlPermissions.RESTRICTED : PERMISSIONS,
-                            JexlScriptObject.class);
-                        builder.permissions(permissions);
-                    engine = builder.create();
-                    ENGINE = new SoftReference<>(engine);
+                    if (!(scriptEngineFactory instanceof JexlScriptEngineFactory)) {
+                        throw new IllegalArgumentException("ScriptEngineFactory is not JexlScriptEngineFactory");
+                    }
+                    JexlScriptEngineFactory factory = (JexlScriptEngineFactory) scriptEngineFactory;
+                    engine = factory.createJexlEngine();
+                    engineReference = new SoftReference<>(engine);
                 }
             }
         }
@@ -367,23 +360,18 @@ public class JexlScriptEngine extends AbstractScriptEngine implements Compilable
      * @since 3.3
      */
     public static void setInstance(final JexlEngine engine) {
-        ENGINE = new SoftReference<>(engine);
+        engineReference = new SoftReference<>(engine);
     }
 
     /**
      * Sets the permissions instance used to create the script engine.
-     * <p>Calling this method will force engine instance re-creation.</p>
-     * <p>To restore 3.2 script behavior:</p>
-     * {@code
-     *         JexlScriptEngine.setPermissions(JexlPermissions.UNRESTRICTED);
-     * }
-     *
-     * @param permissions the permissions instance to use or null to use the {@link JexlBuilder} default
-     * @since 3.3
+     * <p>This method has been considered unsafe and is no longer supported.</p>
+     * @deprecated 3.6.3
+     * @param permissions unused, method will throw
      */
+    @Deprecated
     public static void setPermissions(final JexlPermissions permissions) {
-        PERMISSIONS = permissions;
-        ENGINE = null; // will force recreation
+        throw new UnsupportedOperationException("JexlScriptEngine.setPermissions is unsafe and no longer supported");
     }
 
     /** The JexlScriptObject instance. */
@@ -414,21 +402,21 @@ public class JexlScriptEngine extends AbstractScriptEngine implements Compilable
     public JexlScriptEngine(final ScriptEngineFactory scriptEngineFactory) {
         Objects.requireNonNull(scriptEngineFactory, "scriptEngineFactory");
         parentFactory = scriptEngineFactory;
-        jexlEngine = getEngine();
+        jexlEngine = getEngine(scriptEngineFactory);
         jexlObject = new JexlScriptObject();
     }
 
     @Override
     public CompiledScript compile(final Reader script) throws ScriptException {
         // This is mandated by JSR-223
-        Objects.requireNonNull(script, "script");
+        Objects.requireNonNull(script, SCRIPT);
         return compile(readerToString(script));
     }
 
     @Override
     public CompiledScript compile(final String script) throws ScriptException {
         // This is mandated by JSR-223
-        Objects.requireNonNull(script, "script");
+        Objects.requireNonNull(script, SCRIPT);
         try {
             final JexlScript jexlScript = jexlEngine.createScript(script);
             return new JexlCompiledScript(jexlScript);
@@ -453,7 +441,7 @@ public class JexlScriptEngine extends AbstractScriptEngine implements Compilable
     @Override
     public Object eval(final String script, final ScriptContext context) throws ScriptException {
         // This is mandated by JSR-223 (see SCR.5.5.2   Methods)
-        Objects.requireNonNull(script, "script");
+        Objects.requireNonNull(script, SCRIPT);
         Objects.requireNonNull(context, CONTEXT_KEY);
         // This is mandated by JSR-223 (end of section SCR.4.3.4.1.2 - JexlScript Execution)
         context.setAttribute(CONTEXT_KEY, context, ScriptContext.ENGINE_SCOPE);
diff --git a/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngineFactory.java b/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngineFactory.java
index 1f0b5f7c..7862b36e 100644
--- a/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngineFactory.java
+++ b/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngineFactory.java
@@ -24,6 +24,9 @@ import java.util.List;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
 
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.introspection.JexlPermissions;
 import org.apache.commons.jexl3.parser.StringParser;
 
 /**
@@ -44,9 +47,65 @@ import org.apache.commons.jexl3.parser.StringParser;
  * @since 2.0
  */
 public class JexlScriptEngineFactory implements ScriptEngineFactory {
+    /**
+     * The default factory permissions.
+     */
+    private static JexlPermissions defaultPermissions = null;
+
+    /**
+     * The engine permissions.
+     */
+    private final JexlPermissions permissions;
 
     /** Default constructor */
-    public JexlScriptEngineFactory() {} // Keep Javadoc happy
+    public JexlScriptEngineFactory() { this(null); } // Keep Javadoc happy
+
+    /**
+     * Constructor with permissions.
+     * <p>Meant to reduce dependency to JEXL for extraordinary case of JSR233 </p>
+     * @param jexlPermissions the permissions instance to use or null to use the {@link JexlScriptEngineFactory} default
+     */
+    public JexlScriptEngineFactory(JexlPermissions jexlPermissions) {
+        permissions = jexlPermissions != null ? jexlPermissions : defaultPermissions;
+    }
+
+    /**
+     * @return a new JexlEngine instance
+     */
+    JexlEngine createJexlEngine() {
+        JexlBuilder builder = new JexlBuilder()
+          .strict(true)
+          .safe(false)
+          .logger(JexlScriptEngine.LOG)
+          .cache(JexlScriptEngine.CACHE_SIZE);
+        JexlPermissions p = permissions;
+        if (p == null) {
+            p = defaultPermissions;
+            if (p == null) {
+                p = builder.permissions();
+                if (p == null) {
+                    p = JexlPermissions.RESTRICTED;
+                }
+            }
+        }
+        JexlPermissions required = new JexlPermissions.ClassPermissions(p, JexlScriptEngine.JexlScriptObject.class);
+        builder.permissions(required);
+        return builder.create();
+    }
+
+    /**
+     * Sets the permissions instance used to create the script engine.
+     * <p>To restore 3.2 <em>unsafe</em> script behavior:</p>
+     * {@code
+     *         JexlScriptEngineFactory.setDefaultPermissions(JexlPermissions.UNRESTRICTED);
+     * }
+     *
+     * @param permissions the permissions instance to use or null to use the {@link JexlBuilder} default
+     * @since 3.6.3
+     */
+    public static void setDefaultPermissions(final JexlPermissions permissions) {
+        defaultPermissions = permissions;
+    }
 
     @Override
     public String getEngineName() {
diff --git a/src/site/xdoc/relnotes.xml b/src/site/xdoc/relnotes.xml
index 893503d6..99b53562 100644
--- a/src/site/xdoc/relnotes.xml
+++ b/src/site/xdoc/relnotes.xml
@@ -59,6 +59,30 @@
     <section name="Bugs fixed in 3.6.3:">
       <p>
         <table>
+          <tr>
+            <td>
+              <a href="https://issues.apache.org/jira/browse/JEXL-461">JEXL-461:</a>
+            </td>
+            <td>Updates/improvements to the site documentation for JEXL Syntax.</td>
+          </tr>
+          <tr>
+            <td>
+              <a href="https://issues.apache.org/jira/browse/JEXL-459">JEXL-459:</a>
+            </td>
+            <td>Empty/size functions swallow all exceptions with no trace.</td>
+          </tr>
+          <tr>
+            <td>
+              <a href="https://issues.apache.org/jira/browse/JEXL-458">JEXL-458:</a>
+            </td>
+            <td>Improve permissions expressivity.</td>
+          </tr>
+          <tr>
+            <td>
+              <a href="https://issues.apache.org/jira/browse/JEXL-457">JEXL-457:</a>
+            </td>
+            <td>Reduce default exposure for RESTRICTED JexlPermissions.</td>
+          </tr>
           <tr>
             <td>
               <a href="https://issues.apache.org/jira/browse/JEXL-456">JEXL-456:</a>
@@ -68,6 +92,28 @@
         </table>
       </p>
     </section>
+    <section name="Changes in 3.6.3:">
+      <p>
+        <table>
+          <tr>
+            <td></td>
+            <td>Fix the @return tags in the Javadoc for JexlArithmetic.toBigInteger() overloads.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Bump org.apache.commons:commons-parent from 96 to 102.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Bump commons-logging:commons-logging from 1.3.5 to 1.4.0.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Bump com.google.code.gson:gson from 2.13.2 to 2.14.0.</td>
+          </tr>
+        </table>
+      </p>
+    </section>
 
     <section name="What was new in 3.6.2:">
       <p>
@@ -100,6 +146,17 @@
       </p>
     </section>
 
+    <section name="Changes in 3.6.2:">
+      <p>
+        <table>
+          <tr>
+            <td></td>
+            <td>Bump org.apache.commons:commons-parent from 93 to 96.</td>
+          </tr>
+        </table>
+      </p>
+    </section>
+
     <section name="What was new in 3.6.1:">
       <p>
         JEXL 3.6.1 was a minor release that fixed some bugs.
@@ -137,6 +194,21 @@
       </p>
     </section>
 
+    <section name="Changes in 3.6.1:">
+      <p>
+        <table>
+          <tr>
+            <td></td>
+            <td>Bump org.apache.commons:commons-parent from 91 to 93.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.20.0.</td>
+          </tr>
+        </table>
+      </p>
+    </section>
+
     <section name="What was new in 3.6.0:">
       <p>
         JEXL 3.6.0 introduced a switch statement and expressions (JEXL-440).
@@ -160,21 +232,27 @@
         <table>
           <tr>
             <td>
-              <a href="https://issues.apache.org/jira/browse/JEXL-437">JEXL-447:</a>
+              <a href="https://issues.apache.org/jira/browse/JEXL-448">JEXL-448:</a>
             </td>
-            <td>Regression in script-defined functions</td>
+            <td>Engines caching misses local variables handling and global eviction capability.</td>
+          </tr>
+          <tr>
+            <td>
+              <a href="https://issues.apache.org/jira/browse/JEXL-447">JEXL-447:</a>
+            </td>
+            <td>Regression in script-defined functions.</td>
           </tr>
           <tr>
             <td>
               <a href="https://issues.apache.org/jira/browse/JEXL-446">JEXL-446:</a>
             </td>
-            <td>ClassTool module inspection is too strict</td>
+            <td>ClassTool module inspection is too strict.</td>
           </tr>
           <tr>
             <td>
               <a href="https://issues.apache.org/jira/browse/JEXL-442">JEXL-442:</a>
             </td>
-            <td>Local variables are not resolved in interpolation string expression</td>
+            <td>Local variables are not resolved in interpolation string expression.</td>
           </tr>
           <tr>
             <td>
@@ -186,13 +264,39 @@
             <td>
               <a href="https://issues.apache.org/jira/browse/JEXL-439">JEXL-439:</a>
             </td>
-            <td>When using reference capture, incorrect scoping when local variable redefines a captured symbol</td>
+            <td>When using reference capture, incorrect scoping when local variable redefines a captured symbol.</td>
           </tr>
           <tr>
             <td>
               <a href="https://issues.apache.org/jira/browse/JEXL-437">JEXL-437:</a>
             </td>
-            <td>Semicolons actually not optional between function calls on separate lines</td>
+            <td>Semicolons not actually optional between function calls on separate lines.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>AbstractExecutor.initMarker throws IllegalArgumentException instead of Exception.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Reuse BigInteger constants instead of creating new instances in JexlArithmetic.toBigInteger(Object).</td>
+          </tr>
+        </table>
+      </p>
+    </section>
+    <section name="Changes in 3.6.0:">
+      <p>
+        <table>
+          <tr>
+            <td></td>
+            <td>Bump org.apache.commons:commons-parent from 81 to 91.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.19.0.</td>
+          </tr>
+          <tr>
+            <td></td>
+            <td>Bump com.google.code.gson:gson from 2.13.1 to 2.13.2.</td>
           </tr>
         </table>
       </p>
diff --git a/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java b/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
index 0cac1093..5b60b3ac 100644
--- a/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
+++ b/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
@@ -45,7 +45,6 @@ import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
 
-import org.apache.commons.jexl3.JexlBuilder;
 import org.apache.commons.jexl3.JexlException;
 import org.apache.commons.jexl3.LoggingPermissions;
 import org.apache.commons.jexl3.introspection.JexlPermissions;
@@ -81,9 +80,8 @@ class JexlScriptEngineTest {
 
     @AfterEach
     void tearDown() {
-        JexlBuilder.setDefaultPermissions(null);
         JexlScriptEngine.setInstance(null);
-        JexlScriptEngine.setPermissions(null);
+        JexlScriptEngineFactory.setDefaultPermissions(null);
     }
 
     @Test
@@ -148,7 +146,7 @@ class JexlScriptEngineTest {
     @Test
     void testErrors() throws Exception {
         JexlPermissions permissions = new JexlPermissions.ClassPermissions(Errors.class);
-        JexlScriptEngine.setPermissions(permissions);
+        JexlScriptEngineFactory.setDefaultPermissions(permissions);
         final ScriptEngineManager manager = new ScriptEngineManager();
         final JexlScriptEngine engine = (JexlScriptEngine) manager.getEngineByName("JEXL");
         engine.put("errors", new Errors());
@@ -257,7 +255,7 @@ class JexlScriptEngineTest {
     }
     @Test
     void testScriptingInstance0() throws Exception {
-        JexlScriptEngine.setPermissions(JexlPermissions.UNRESTRICTED);
+        JexlScriptEngineFactory.setDefaultPermissions(JexlPermissions.UNRESTRICTED);
         final ScriptEngineManager manager = new ScriptEngineManager();
         final ScriptEngine engine = manager.getEngineByName("jexl3");
         final Long time2 = (Long) engine.eval(
@@ -269,7 +267,7 @@ class JexlScriptEngineTest {
     @Test
     void testScriptingPermissions1() throws Exception {
         // shows what is required to access System.currentTimeMillis()
-        JexlScriptEngine.setPermissions(new LoggingPermissions(
+        JexlScriptEngineFactory.setDefaultPermissions(new LoggingPermissions(
             JexlPermissions.RESTRICTED.compose(
                 "javax.script { +SimpleScriptContext { getClass(); } }"
                     + "java.lang { "