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 <[email protected]>
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 { "