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 2019/11/18 16:32:33 UTC
[commons-jexl] branch master updated: JEXL-307: as a default, copy
options handled of context used at runtime to reduce the possibility of
artificially complex mistakes;
add an explicit flag to still allow purposeful usage Task #JEXL-307 -
Variable redeclaration option
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 9800c05 JEXL-307: as a default, copy options handled of context used at runtime to reduce the possibility of artificially complex mistakes; add an explicit flag to still allow purposeful usage Task #JEXL-307 - Variable redeclaration option
9800c05 is described below
commit 9800c05277675e3edbfe5d1246141cdfab0e78e1
Author: henrib <he...@apache.org>
AuthorDate: Mon Nov 18 17:31:11 2019 +0100
JEXL-307: as a default, copy options handled of context used at runtime to reduce the possibility of artificially complex mistakes; add an explicit flag to still allow purposeful usage
Task #JEXL-307 - Variable redeclaration option
---
.../java/org/apache/commons/jexl3/JexlContext.java | 8 ++--
.../java/org/apache/commons/jexl3/JexlOptions.java | 25 +++++++++++-
.../org/apache/commons/jexl3/internal/Engine.java | 44 ++++++++++++----------
.../org/apache/commons/jexl3/AnnotationTest.java | 1 +
.../java/org/apache/commons/jexl3/LexicalTest.java | 17 +++++++++
5 files changed, 69 insertions(+), 26 deletions(-)
diff --git a/src/main/java/org/apache/commons/jexl3/JexlContext.java b/src/main/java/org/apache/commons/jexl3/JexlContext.java
index ce730f7..2f4d69e 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlContext.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlContext.java
@@ -151,10 +151,10 @@ public interface JexlContext {
/**
* Retrieves the current set of options though the context.
* <p>
- * This method will be called once at beginning of evaluation and the
- * JexlOptions instance kept as a property of the evaluator;
- * the JexlOptions instance is free to alter its boolean flags during
- * execution.
+ * This method will be called once at beginning of evaluation and an interpreter private copy
+ * of the context handled JexlOptions instance used for the duration of the execution;
+ * the context handled JexlOptions instance being only used as the source of that copy,
+ * it can safely alter its boolean flags during execution with no effect, avoiding any behavior ambiguity.
* @return the engine options
*/
JexlOptions getEngineOptions();
diff --git a/src/main/java/org/apache/commons/jexl3/JexlOptions.java b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
index c650e9b..0682e4e 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlOptions.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
@@ -31,12 +31,15 @@ import org.apache.commons.jexl3.internal.Engine;
* <li>lexicalShade: whether local variables shade global ones even outside their scope</li>
* <li>strict: whether unknown or unsolvable identifiers are errors</li>
* <li>strictArithmetic: whether null as operand is an error</li>
+ * <li>immutable: whether these options can be modified at runtime during execution (expert)</li>
* </ul>
* The sensible default is cancellable, strict and strictArithmetic.
* <p>This interface replaces the now deprecated JexlEngine.Options.
* @since 3.2
*/
public final class JexlOptions {
+ /** The shared isntance bit. */
+ private static final int SHARED = 7;
/** The local shade bit. */
private static final int SHADE = 6;
/** The antish var bit. */
@@ -53,10 +56,10 @@ public final class JexlOptions {
private static final int CANCELLABLE = 0;
/** The flags names ordered. */
private static final String[] NAMES = {
- "cancellable", "strict", "silent", "safe", "lexical", "antish", "lexicalShade"
+ "cancellable", "strict", "silent", "safe", "lexical", "antish", "lexicalShade", "sharedInstance"
};
/** Default mask .*/
- private static int DEFAULT = 1 /*<< CANCELLABLE*/ | 1 << STRICT | 1 << ANTISH | 1 << SAFE;
+ private static int DEFAULT = 1 /*<< CANCELLABLE*/ | 1 << STRICT | 1 << ANTISH | 1 << SAFE | 1 << SHARED;
/** The arithmetic math context. */
private MathContext mathContext = null;
/** The arithmetic math scale. */
@@ -334,6 +337,24 @@ public final class JexlOptions {
}
/**
+ * Whether these options are immutable at runtime.
+ * <p>Expert mode; allows instance handled through context to be shared
+ * instead of copied.
+ * @param flag true if shared, false if not
+ */
+ public void setSharedInstance(boolean flag) {
+ flags = set(SHARED, flags, flag);
+ }
+
+ /**
+ * @return false if a copy of these options is used during execution,
+ * true if those can potentially be modified
+ */
+ public boolean isSharedInstance() {
+ return isSet(SHARED, flags);
+ }
+
+ /**
* Set options from engine.
* @param jexl the engine
* @return this instance
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 e068eb1..0296777 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -301,32 +301,36 @@ public class Engine extends JexlEngine {
}
/**
- * Extracts the engine evaluation options from context.
+ * Extracts the engine evaluation options from context if available, the engine
+ * options otherwise.
+ * <p>This creates a copy of the options so they are immutable during
+ * execution.
* @param context the context
* @return the options if any
*/
JexlOptions options(JexlContext context) {
- JexlOptions jexlo = null;
+ // Make a copy of the handled options if any
if (context instanceof JexlContext.OptionsHandle) {
- jexlo = ((JexlContext.OptionsHandle) context).getEngineOptions();
+ JexlOptions jexlo = ((JexlContext.OptionsHandle) context).getEngineOptions();
+ if (jexlo != null) {
+ return jexlo.isSharedInstance()? jexlo : jexlo.copy();
+ }
}
- if (jexlo == null) {
- jexlo = options;
- /** The following block for compatibility between 3.1 and 3.2*/
- if (context instanceof JexlEngine.Options) {
- jexlo = jexlo.copy();
- JexlEngine jexl = this;
- JexlEngine.Options opts = (JexlEngine.Options) context;
- jexlo.setCancellable(option(opts.isCancellable(), jexl.isCancellable()));
- jexlo.setSilent(option(opts.isSilent(), jexl.isSilent()));
- jexlo.setStrict(option(opts.isStrict(), jexl.isStrict()));
- JexlArithmetic jexla = jexl.getArithmetic();
- jexlo.setStrictArithmetic(option(opts.isStrictArithmetic(), jexla.isStrict()));
- jexlo.setMathContext(opts.getArithmeticMathContext());
- jexlo.setMathScale(opts.getArithmeticMathScale());
- }
+ // The following block for compatibility between 3.1 and 3.2
+ else if (context instanceof JexlEngine.Options) {
+ JexlOptions jexlo = options.copy();
+ JexlEngine jexl = this;
+ JexlEngine.Options opts = (JexlEngine.Options) context;
+ jexlo.setCancellable(option(opts.isCancellable(), jexl.isCancellable()));
+ jexlo.setSilent(option(opts.isSilent(), jexl.isSilent()));
+ jexlo.setStrict(option(opts.isStrict(), jexl.isStrict()));
+ JexlArithmetic jexla = jexl.getArithmetic();
+ jexlo.setStrictArithmetic(option(opts.isStrictArithmetic(), jexla.isStrict()));
+ jexlo.setMathContext(opts.getArithmeticMathContext());
+ jexlo.setMathScale(opts.getArithmeticMathScale());
+ return jexlo;
}
- return jexlo;
+ return options;
}
/**
@@ -382,7 +386,7 @@ public class Engine extends JexlEngine {
for(Map.Entry<String, Object> pragma : pragmas.entrySet()) {
String key = pragma.getKey();
Object value = pragma.getValue();
- if (PRAGMA_OPTIONS.equals(key) && opts != null) {
+ if (PRAGMA_OPTIONS.equals(key)) {
if (value instanceof String) {
String[] vs = ((String) value).split(" ");
opts.setFlags(vs);
diff --git a/src/test/java/org/apache/commons/jexl3/AnnotationTest.java b/src/test/java/org/apache/commons/jexl3/AnnotationTest.java
index a4aebb5..e77acef 100644
--- a/src/test/java/org/apache/commons/jexl3/AnnotationTest.java
+++ b/src/test/java/org/apache/commons/jexl3/AnnotationTest.java
@@ -121,6 +121,7 @@ public class AnnotationTest extends JexlTestCase {
OptAnnotationContext jc = new OptAnnotationContext();
JexlOptions options = jc.getEngineOptions();
jc.getEngineOptions().set(JEXL);
+ options.setSharedInstance(true);
JexlScript e;
Object r;
e = JEXL.createScript("(s, v)->{ @strict(s) @silent(v) var x = y ; 42; }");
diff --git a/src/test/java/org/apache/commons/jexl3/LexicalTest.java b/src/test/java/org/apache/commons/jexl3/LexicalTest.java
index 891393a..d950d3a 100644
--- a/src/test/java/org/apache/commons/jexl3/LexicalTest.java
+++ b/src/test/java/org/apache/commons/jexl3/LexicalTest.java
@@ -387,4 +387,21 @@ public class LexicalTest {
}
}
+ @Test
+ public void testLexicalOption() throws Exception {
+ JexlFeatures f= new JexlFeatures();
+ JexlEngine jexl = new JexlBuilder().features(f).strict(true).create();
+ JexlEvalContext ctxt = new JexlEvalContext();
+ JexlOptions options = ctxt.getEngineOptions();
+ options.setLexical(true);
+ options.setLexicalShade(true);
+ ctxt.set("options", options);
+ JexlScript script = jexl.createScript("{var x = 42;} options.lexical = false; x");
+ try {
+ Object result = script.execute(ctxt);
+ Assert.fail("setting options.lexical should have no effect during execution");
+ } catch(JexlException xf) {
+ Assert.assertNotNull(xf);
+ }
+ }
}