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 2025/07/03 16:43:33 UTC
(commons-jexl) branch JEXL-440 updated: JEXL-440 : added constants/enum handling defined through imports usable in case expression/statement; - enum constant and (public) static final fields are usable as values in case expression/statement; - import is now stricter, will verify package or class is visible (apply permission) and throw if not; - light refactoring around ClassNameResolve/ClassConstantResolver/ConstantResolverFactory (moved to JexlUberspect); - also fixed autoSemicolon issue (JEXL-437);
This is an automated email from the ASF dual-hosted git repository.
henrib pushed a commit to branch JEXL-440
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/JEXL-440 by this push:
new b85369ac JEXL-440 : added constants/enum handling defined through imports usable in case expression/statement; - enum constant and (public) static final fields are usable as values in case expression/statement; - import is now stricter, will verify package or class is visible (apply permission) and throw if not; - light refactoring around ClassNameResolve/ClassConstantResolver/ConstantResolverFactory (moved to JexlUberspect); - also fixed autoSemicolon issue (JEXL-437);
b85369ac is described below
commit b85369ac1b368cf6d9187f93343cf7511d947f41
Author: Henrib <hb...@gmail.com>
AuthorDate: Thu Jul 3 18:43:21 2025 +0200
JEXL-440 : added constants/enum handling defined through imports usable in case expression/statement;
- enum constant and (public) static final fields are usable as values in case expression/statement;
- import is now stricter, will verify package or class is visible (apply permission) and throw if not;
- light refactoring around ClassNameResolve/ClassConstantResolver/ConstantResolverFactory (moved to JexlUberspect);
- also fixed autoSemicolon issue (JEXL-437);
---
RELEASE-NOTES.txt | 23 +++
src/changes/changes.xml | 10 +-
.../java/org/apache/commons/jexl3/JexlContext.java | 11 +-
.../org/apache/commons/jexl3/JexlFeatures.java | 7 +-
.../java/org/apache/commons/jexl3/JexlOptions.java | 4 +-
.../org/apache/commons/jexl3/internal/Engine.java | 53 ++++---
.../commons/jexl3/internal/FqcnResolver.java | 165 ++++++++++++---------
.../apache/commons/jexl3/internal/Interpreter.java | 2 +-
.../commons/jexl3/internal/InterpreterBase.java | 8 +-
.../internal/introspection/FieldGetExecutor.java | 13 ++
.../jexl3/introspection/JexlPropertyGet.java | 8 +
.../commons/jexl3/introspection/JexlUberspect.java | 50 ++++++-
.../apache/commons/jexl3/parser/JexlParser.java | 73 +++++++--
.../commons/jexl3/parser/JexlScriptParser.java | 1 +
.../org/apache/commons/jexl3/parser/Parser.jjt | 64 +++++---
src/site/xdoc/relnotes35.xml | 32 +++-
.../org/apache/commons/jexl3/ArithmeticTest.java | 130 ++++++++--------
.../org/apache/commons/jexl3/FeaturesTest.java | 38 ++---
.../org/apache/commons/jexl3/Issues200Test.java | 82 +++++-----
.../org/apache/commons/jexl3/Issues400Test.java | 70 ++++++++-
.../java/org/apache/commons/jexl3/JexlTest.java | 80 +++++-----
.../apache/commons/jexl3/internal/FqcnTest.java | 94 ++++++++++++
.../apache/commons/jexl3/internal/RangeTest.java | 16 +-
23 files changed, 714 insertions(+), 320 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index eff4c7c2..1e6f0903 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -29,6 +29,29 @@ Download page: https://commons.apache.org/proper/commons-jexl/download_jexl.cgi
Have fun!
-Apache Commons Team
+========================================================================================================================
+Release 3.6.0
+========================================================================================================================
+
+Version 3.6.0 is a minor release.
+
+Compatibility with previous releases
+====================================
+Version 3.6.0 is source and binary compatible with 3.5.
+
+
+What's new in 3.6.0:
+====================
+Switch / case statements and expressions have been added to JEXL.
+
+New Features in 3.6.0:
+======================
+* JEXL-440: Switch/case statement and expression
+Bugs Fixed in 3.6.0:
+====================
+* JEXL-437: Semicolons not actually optional between function calls on separate lines
+
+
========================================================================================================================
Release 3.5.0
========================================================================================================================
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d1615c09..1ee93191 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -27,11 +27,17 @@
<author email="dev@commons.apache.org">Commons Developers</author>
</properties>
<body>
- <release version="3.5.1" date="YYYY-MM-DD" description="This is a feature and maintenance release. Java 8 or later is required.">
+ <release version="3.6.0" date="YYYY-MM-DD" description="This is a feature and maintenance release. Java 8 or later is required.">
<!-- FIX -->
- <action type="fix" dev="ggregory" due-to="Gary Gregory">org.apache.commons.jexl3.internal.introspection.AbstractExecutor.initMarker(Class, String, Class...) throws IllegalArgumentException instead of Error.</action>
+ <action dev="henrib" type="fix" issue="JEXL-437" due-to="William Price">
+ Semicolons not actually optional between function calls on separate lines
+ </action>
+ <action type="fix" dev="ggregory" due-to="Gary Gregory">oac....AbstractExecutor.initMarker(Class, String, Class...) throws IllegalArgumentException instead of Error.</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Reuse BigInteger constants instead of creating new instances in org.apache.commons.jexl3.JexlArithmetic.toBigInteger(Object).</action>
<!-- ADD -->
+ <action dev="henrib" type="add" issue="JEXL-440">
+ Switch statement & expressions
+ </action>
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 81 to 84 #344.</action>
</release>
diff --git a/src/main/java/org/apache/commons/jexl3/JexlContext.java b/src/main/java/org/apache/commons/jexl3/JexlContext.java
index 1fb92768..9e1e7512 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlContext.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlContext.java
@@ -17,6 +17,8 @@
package org.apache.commons.jexl3;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
+
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -83,14 +85,7 @@ public interface JexlContext {
* A marker interface that solves a simple class name into a fully-qualified one.
* @since 3.3
*/
- interface ClassNameResolver {
- /**
- * Resolves a class name.
- * @param name the simple class name
- * @return the fully qualified class name
- */
- String resolveClassName(String name);
- }
+ interface ClassNameResolver extends JexlUberspect.ClassNameResolver {}
/**
* A marker interface of the JexlContext that processes module definitions.
diff --git a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
index eb735915..1eb51bdd 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
@@ -725,9 +725,11 @@ public final class JexlFeatures {
* may be missing an operator or that the intent is not clear.
* </p>
* @param flag true to enable, false to disable
+ * @return this features instance
*/
- public void setAmbiguousStatement(final boolean flag) {
+ public JexlFeatures ambiguousStatement(final boolean flag) {
setFeature(AMBIGUOUS_STATEMENT, flag);
+ return this;
}
/**
@@ -740,7 +742,8 @@ public final class JexlFeatures {
* @return true if statements can be ambiguous, false otherwise
*/
public boolean supportsAmbiguousStatement() {
- return getFeature(AMBIGUOUS_STATEMENT);
+ boolean sas = getFeature(AMBIGUOUS_STATEMENT);
+ return sas;
}
/**
diff --git a/src/main/java/org/apache/commons/jexl3/JexlOptions.java b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
index afc3f3b2..2a3a1741 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlOptions.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
@@ -334,9 +334,9 @@ public final class JexlOptions {
*/
public JexlOptions set(final JexlEngine jexl) {
if (jexl instanceof Engine) {
- ((Engine) jexl).optionsSet(this);
+ return ((Engine) jexl).optionsSet(this);
}
- return this;
+ throw new UnsupportedOperationException("JexlEngine is not an Engine instance: " + jexl.getClass().getName());
}
/**
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 4d966d51..b651ac14 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -23,6 +23,7 @@ import static org.apache.commons.jexl3.parser.JexlParser.PRAGMA_OPTIONS;
import java.nio.charset.Charset;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -71,7 +72,7 @@ import org.apache.commons.logging.LogFactory;
* A JexlEngine implementation.
* @since 2.0
*/
-public class Engine extends JexlEngine {
+public class Engine extends JexlEngine implements JexlUberspect.ConstantResolverFactory {
/**
* Gets the default instance of Uberspect.
* <p>This is lazily initialized to avoid building a default instance if there
@@ -177,12 +178,15 @@ public class Engine extends JexlEngine {
public static Uberspect getUberspect(final Log logger, final JexlUberspect.ResolverStrategy strategy) {
return getUberspect(logger, strategy, null);
}
+
/**
* Gets the default instance of Uberspect.
* <p>This is lazily initialized to avoid building a default instance if there
- * is no use for it. The main reason for not using the default Uberspect instance is to
- * be able to use a (low level) introspector created with a given logger
- * instead of the default one and even more so for with a different (restricted) set of permissions.</p>
+ * is no use for it.</p>
+ * <lu>The main reason for not using the default Uberspect instance are:
+ * <li>Using a (low level) introspector created with a given logger instead of the default one</li>
+ * <li>Using a (restricted) set of permissions</li>
+ * </lu>
* @param logger the logger to use for the underlying Uberspect
* @param strategy the property resolver strategy
* @param permissions the introspection permissions
@@ -762,6 +766,13 @@ public class Engine extends JexlEngine {
return doCreateInstance(clazz, args);
}
+ @Override
+ public JexlUberspect.ClassConstantResolver createConstantResolver(Collection<String> imports) {
+ return imports == null || imports.isEmpty()
+ ? classNameSolver
+ : new FqcnResolver(classNameSolver).importPackages(imports);
+ }
+
/**
* Sets options from this engine options.
* @param opts the options to set
@@ -810,21 +821,27 @@ public class Engine extends JexlEngine {
}
}
final JexlInfo ninfo = info == null && debug ? createInfo() : info;
- // if parser not in use...
- if (parsing.compareAndSet(false, true)) {
- try {
- // lets parse
- script = parser.parse(ninfo, features, src, scope);
- } finally {
- // no longer in use
- parsing.set(false);
+ JexlEngine se = putThreadEngine(this);
+ try {
+ // if parser not in use...
+ if (parsing.compareAndSet(false, true)) {
+ try {
+ // lets parse
+ script = parser.parse(ninfo, features, src, scope);
+ } finally {
+ // no longer in use
+ parsing.set(false);
+ }
+ } else {
+ // ...otherwise parser was in use, create a new temporary one
+ script = parserFactory.get().parse(ninfo, features, src, scope);
}
- } else {
- // ...otherwise parser was in use, create a new temporary one
- script = parserFactory.get().parse(ninfo, features, src, scope);
- }
- if (source != null) {
- cache.put(source, script);
+ if (source != null) {
+ cache.put(source, script);
+ }
+ } finally {
+ // restore thread local engine
+ putThreadEngine(se);
}
return script;
}
diff --git a/src/main/java/org/apache/commons/jexl3/internal/FqcnResolver.java b/src/main/java/org/apache/commons/jexl3/internal/FqcnResolver.java
index 65f3644f..817ddfe9 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/FqcnResolver.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/FqcnResolver.java
@@ -16,40 +16,37 @@
*/
package org.apache.commons.jexl3.internal;
-import java.util.HashMap;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.introspection.JexlPropertyGet;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
+
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.apache.commons.jexl3.JexlContext;
-import org.apache.commons.jexl3.introspection.JexlUberspect;
+import java.util.concurrent.ConcurrentHashMap;
/**
- * Helper resolving a simple class name into a fully-qualified class name (hence FqcnResolver) using
- * package names as roots of import.
- * <p>This only keeps names of classes to avoid any class loading/reloading/permissions issue.</p>
+ * Helper resolving a simple class name into a Fully Qualified Class Name (hence FqcnResolver) using
+ * package names and classes as roots of import.
+ * <p>This only keeps the names of the classes to avoid any class loading/reloading/permissions issue.</p>
*/
- final class FqcnResolver implements JexlContext.ClassNameResolver {
+public class FqcnResolver implements JexlUberspect.ClassConstantResolver {
/**
- * The class loader.
+ * The uberspect.
*/
private final JexlUberspect uberspect;
- /**
- * A lock for RW concurrent ops.
- */
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* The set of packages to be used as import roots.
*/
- private final Set<String> imports = new LinkedHashSet<>();
+ private final Set<String> imports = Collections.synchronizedSet(new LinkedHashSet<>());
/**
* The map of solved fqcns based on imports keyed on (simple) name,
- * valued as fully-qualified class name.
+ * valued as fully qualified class name.
*/
- private final Map<String, String> fqcns = new HashMap<>();
+ private final Map<String, String> fqcns = new ConcurrentHashMap<>();
/**
* Optional parent solver.
*/
@@ -62,19 +59,18 @@ import org.apache.commons.jexl3.introspection.JexlUberspect;
* @throws NullPointerException if parent solver is null
*/
FqcnResolver(final FqcnResolver solver) {
- Objects.requireNonNull(solver, "solver");
- this.parent = solver;
+ this.parent = Objects.requireNonNull(solver, "solver");
this.uberspect = solver.uberspect;
}
/**
* Creates a class name solver.
*
- * @param uber the optional class loader
+ * @param uber the optional class loader
* @param packages the optional package names
*/
FqcnResolver(final JexlUberspect uber, final Iterable<String> packages) {
- this.uberspect = uber;
+ this.uberspect = Objects.requireNonNull(uber, "uberspect");
this.parent = null;
importCheck(packages);
}
@@ -88,42 +84,35 @@ import org.apache.commons.jexl3.introspection.JexlUberspect;
String getQualifiedName(final String name) {
String fqcn;
if (parent != null && (fqcn = parent.getQualifiedName(name)) != null) {
- return fqcn;
- }
- lock.readLock().lock();
- try {
- fqcn = fqcns.get(name);
- } finally {
- lock.readLock().unlock();
+ return fqcn;
}
- if (fqcn == null) {
- final ClassLoader loader = uberspect.getClassLoader();
- for (final String pkg : imports) {
- Class<?> clazz;
- try {
- clazz = loader.loadClass(pkg + "." + name);
- } catch (final ClassNotFoundException e) {
- // not in this package
- continue;
- }
- // solved it, insert in map and return
+ return fqcns.computeIfAbsent(name, this::solveClassName);
+ }
+
+ /**
+ * Attempts to solve a fully qualified class name from a simple class name.
+ * <p>It tries to solve the class name as package.classname or package$classname (inner class).</p>
+ *
+ * @param name the simple class name
+ * @return the fully qualified class name or null if not found
+ */
+ private String solveClassName(String name) {
+ for (final String pkg : imports) {
+ // try package.classname or fqcn$classname (inner class)
+ for (char dot : new char[]{'.', '$'}) {
+ Class<?> clazz = uberspect.getClassByName(pkg + dot + name);
+ // solved it
if (clazz != null) {
- fqcn = clazz.getName();
- lock.writeLock().lock();
- try {
- fqcns.put(name, fqcn);
- } finally {
- lock.writeLock().unlock();
- }
- break;
+ return clazz.getName();
}
}
}
- return fqcn;
+ return null;
}
/**
- * Adds a collection of packages as import root, checks the names are one of a package.
+ * Adds a collection of packages/classes as import root, check each name point to one or the other.
+ *
* @param names the package names
*/
private void importCheck(final Iterable<String> names) {
@@ -133,14 +122,25 @@ import org.apache.commons.jexl3.introspection.JexlUberspect;
}
/**
- * Adds a package as import root, checks the name if one of a package.
+ * Adds a package as import root, checks the name points to a package or a class.
+ *
* @param name the package name
*/
private void importCheck(final String name) {
+ if (name == null || name.isEmpty()) {
+ return;
+ }
// check the package name actually points to a package to avoid clutter
- if (name != null && Package.getPackage(name) != null) {
- imports.add(name);
+ Package pkg = Package.getPackage(name);
+ if (pkg == null) {
+ // if it is a class, solve it now
+ Class<?> clazz = uberspect.getClassByName(name);
+ if (clazz == null) {
+ throw new JexlException(null, "Cannot import '" + name + "' as it is neither a package nor a class");
+ }
+ fqcns.put(name, clazz.getName());
}
+ imports.add(name);
}
/**
@@ -151,15 +151,14 @@ import org.apache.commons.jexl3.introspection.JexlUberspect;
*/
FqcnResolver importPackages(final Iterable<String> packages) {
if (packages != null) {
- lock.writeLock().lock();
- try {
- if (parent == null) {
- importCheck(packages);
- } else {
- packages.forEach(pkg ->{ if (!parent.isImporting(pkg)) { importCheck(pkg); }});
- }
- } finally {
- lock.writeLock().unlock();
+ if (parent == null) {
+ importCheck(packages);
+ } else {
+ packages.forEach(pkg -> {
+ if (!parent.isImporting(pkg)) {
+ importCheck(pkg);
+ }
+ });
}
}
return this;
@@ -175,16 +174,46 @@ import org.apache.commons.jexl3.introspection.JexlUberspect;
if (parent != null && parent.isImporting(pkg)) {
return true;
}
- lock.readLock().lock();
- try {
- return imports.contains(pkg);
- } finally {
- lock.readLock().unlock();
- }
+ return imports.contains(pkg);
}
@Override
public String resolveClassName(final String name) {
return getQualifiedName(name);
}
+
+ @Override
+ public Object resolveConstant(final String cname) {
+ return getConstant(cname.split("\\."));
+ }
+
+ private Object getConstant(final String... ids) {
+ if (ids.length == 1) {
+ final String pname = ids[0];
+ for (String cname : fqcns.keySet()) {
+ Object constant = getConstant(cname, pname);
+ if (constant != JexlEngine.TRY_FAILED) {
+ return constant;
+ }
+ }
+ } else if (ids.length == 2) {
+ String cname = ids[0];
+ String id = ids[1];
+ String fqcn = resolveClassName(cname);
+ if (fqcn != null) {
+ Class<?> clazz = uberspect.getClassByName(fqcn);
+ if (clazz != null) {
+ JexlPropertyGet getter = uberspect.getPropertyGet(clazz, id);
+ if (getter != null && getter.isConstant()) {
+ try {
+ return getter.invoke(clazz);
+ } catch (Exception xany) {
+ // ignore
+ }
+ }
+ }
+ }
+ }
+ return JexlEngine.TRY_FAILED;
+ }
}
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 decbc26e..9d010494 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -932,7 +932,7 @@ public class Interpreter extends InterpreterBase {
if (fqcn != null) {
return fqcn;
}
- // context may be solving class name ?
+ // context may be solving class name?
if (context instanceof JexlContext.ClassNameResolver) {
final JexlContext.ClassNameResolver resolver = (JexlContext.ClassNameResolver) context;
fqcn = resolver.resolveClassName(name);
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 d7b0aff8..747700ed 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
@@ -16,7 +16,6 @@
*/
package org.apache.commons.jexl3.internal;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -309,7 +308,7 @@ public abstract class InterpreterBase extends ParserVisitor {
/** The namespace resolver. */
protected final JexlContext.NamespaceResolver ns;
/** The class name resolver. */
- protected final JexlContext.ClassNameResolver fqcnSolver;
+ protected final JexlUberspect.ClassNameResolver fqcnSolver;
/** The operators evaluation delegate. */
protected final JexlOperator.Uberspect operators;
/** The map of 'prefix:function' to object resolving as namespaces. */
@@ -355,10 +354,7 @@ public abstract class InterpreterBase extends ParserVisitor {
}
this.operators = ops;
// the import package facility
- final Collection<String> imports = options.getImports();
- this.fqcnSolver = imports.isEmpty()
- ? engine.classNameSolver
- : new FqcnResolver(engine.classNameSolver).importPackages(imports);
+ this.fqcnSolver = engine.createConstantResolver(options.getImports());
}
/**
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/FieldGetExecutor.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/FieldGetExecutor.java
index 7f275165..b6074c0e 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/FieldGetExecutor.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/FieldGetExecutor.java
@@ -21,6 +21,9 @@ import java.lang.reflect.Field;
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
+import static java.lang.reflect.Modifier.isFinal;
+import static java.lang.reflect.Modifier.isStatic;
+
/**
* A JexlPropertyGet for public fields.
*/
@@ -65,6 +68,16 @@ public final class FieldGetExecutor implements JexlPropertyGet {
return true;
}
+ @Override
+ public boolean isConstant() {
+ if (field.isEnumConstant()) {
+ return true;
+ }
+ final int modifiers = field.getModifiers();
+ // public static final fields are (considered) constants
+ return isFinal(modifiers) && isStatic(modifiers);
+ }
+
@Override
public boolean tryFailed(final Object rval) {
return rval == Uberspect.TRY_FAILED;
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java
index b6d0e9d2..9cb0b2cb 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java
@@ -46,6 +46,14 @@ public interface JexlPropertyGet {
*/
boolean isCacheable();
+ /**
+ * Checks whether this JexlPropertyGet returns a constant.
+ * @return true if invoking this getter will always return the same value, false otherwise
+ */
+ default boolean isConstant() {
+ return false;
+ }
+
/**
* Checks whether a tryInvoke failed or not.
*
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
index d28ebdf8..669ab717 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
@@ -18,6 +18,7 @@
package org.apache.commons.jexl3.introspection;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -48,7 +49,7 @@ public interface JexlUberspect {
/** Seeks map methods get/put. */
MAP,
- /** Seeks list methods get/set. */
+ /** Seeks list methods to get/set. */
LIST,
/** Seeks any get/{set,put} method (quacking like a list or a map). */
@@ -76,6 +77,45 @@ public interface JexlUberspect {
}
}
+ /**
+ * A marker interface that solves a simple class name into a fully qualified one.
+ * <p>The base implementation uses imports.</p>
+ * @since 3.3
+ */
+ interface ClassNameResolver {
+ /**
+ * Resolves a class name.
+ * @param name the simple class name
+ * @return the fully qualified class name
+ */
+ String resolveClassName(String name);
+ }
+
+ /**
+ * A marker interface that solves a class constant by name.
+ * <p>The base implementation uses imports to solve enums and public static final fields.</p>
+ * @since 3.6
+ */
+ interface ClassConstantResolver extends ClassNameResolver {
+ /**
+ * Resolves a constant by its name.
+ * @param name the constant name, a qualified name
+ * @return the constant value or TRY_FAILED if not found
+ */
+ Object resolveConstant(String name);
+ }
+
+ /**
+ * The factory type for creating constant resolvers.
+ */
+ interface ConstantResolverFactory {
+ /**
+ * Creates a constant resolver.
+ * @return a constant resolver
+ */
+ ClassConstantResolver createConstantResolver(Collection<String> imports);
+ }
+
/**
* Abstracts getting property setter and getter.
* <p>
@@ -115,7 +155,7 @@ public interface JexlUberspect {
/**
* Determines property resolution strategy.
*
- * <p>To use a strategy instance, you have to set it at engine creation using
+ * <p>To use a strategy, you have to set it at engine creation using
* {@link org.apache.commons.jexl3.JexlBuilder#strategy(JexlUberspect.ResolverStrategy)}
* as in:</p>
*
@@ -127,9 +167,9 @@ public interface JexlUberspect {
/**
* Applies this strategy to a list of resolver types.
*
- * @param operator the property access operator, may be null
+ * @param operator the property access operator, can be null
* @param obj the instance we seek to obtain a property setter/getter from, cannot be null
- * @return the ordered list of resolvers types, must not be null
+ * @return the ordered list of resolver types, cannot be null
*/
List<PropertyResolver> apply(JexlOperator operator, Object obj);
}
@@ -226,7 +266,7 @@ public interface JexlUberspect {
default Class<?> getClassByName(final String className) {
try {
return Class.forName(className, false, getClassLoader());
- } catch (final ClassNotFoundException xignore) {
+ } catch (final ClassNotFoundException ignore) {
return null;
}
}
diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
index 6a1e823a..a073afc8 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
@@ -20,6 +20,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
@@ -27,6 +28,7 @@ import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -37,6 +39,7 @@ import org.apache.commons.jexl3.JexlFeatures;
import org.apache.commons.jexl3.JexlInfo;
import org.apache.commons.jexl3.internal.LexicalScope;
import org.apache.commons.jexl3.internal.Scope;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
/**
* The base class for parsing, manages the parameter/local variable frame.
@@ -175,54 +178,83 @@ public abstract class JexlParser extends StringParser implements JexlScriptParse
* The source being processed.
*/
protected String source;
-
/**
* The map of named registers aka script parameters.
* <p>Each parameter is associated to a register and is materialized
* as an offset in the registers array used during evaluation.</p>
*/
protected Scope scope;
-
/**
* When parsing inner functions/lambda, need to stack the scope (sic).
*/
protected final Deque<Scope> scopes = new ArrayDeque<>();
-
/**
* The list of pragma declarations.
*/
protected Map<String, Object> pragmas;
+ /**
+ * The optional class name and constant resolver.
+ */
+ protected JexlUberspect.ClassConstantResolver fqcnResolver = null;
+ /**
+ * The list of imports.
+ * <p>Imports are used to resolve simple class names into fully qualified class names.</p>
+ */
+ protected List<String> imports = new ArrayList<>();
+
+
+ void addImport(String importName) {
+ if (importName != null && !importName.isEmpty()) {
+ if (imports == null) {
+ imports = new ArrayList<>();
+ }
+ if (!imports.contains(importName)) {
+ imports.add(importName);
+ }
+ }
+ }
+
+ Object resolveConstant(String name) {
+ JexlUberspect.ClassConstantResolver resolver = fqcnResolver;
+ if (resolver == null) {
+ JexlEngine engine = JexlEngine.getThreadEngine();
+ if (engine instanceof JexlUberspect.ConstantResolverFactory) {
+ fqcnResolver = resolver = ((JexlUberspect.ConstantResolverFactory) engine).createConstantResolver(imports);
+ }
+ }
+ return resolver != null
+ ? resolver.resolveConstant(name)
+ : JexlEngine.TRY_FAILED;
+ }
+ /**
+ * Whether automatic semicolon insertion is enabled.
+ */
+ protected boolean autoSemicolon = true;
/**
* The known namespaces.
*/
protected Set<String> namespaces;
-
/**
* The number of nested loops.
*/
protected int loopCount;
-
/**
* Stack of parsing loop counts.
*/
protected final Deque<Integer> loopCounts = new ArrayDeque<>();
-
/**
* The current lexical block.
*/
protected LexicalUnit block;
-
/**
* Stack of lexical blocks.
*/
protected final Deque<LexicalUnit> blocks = new ArrayDeque<>();
-
/**
* The map of lexical to functional blocks.
*/
protected final Map<LexicalUnit, Scope> blockScopes = new IdentityHashMap<>();
-
/**
* The name of the null case constant.
*/
@@ -441,6 +473,8 @@ public abstract class JexlParser extends StringParser implements JexlScriptParse
scopes.clear();
pragmas = null;
namespaces = null;
+ fqcnResolver = null;
+ imports.clear();
loopCounts.clear();
loopCount = 0;
blocks.clear();
@@ -795,6 +829,27 @@ public abstract class JexlParser extends StringParser implements JexlScriptParse
return scope != null && scope.getSymbol(name) != null;
}
+ /**
+ * Checks whether a statement is ambiguous.
+ * <p>
+ * This is used to detect statements that are not terminated by a semicolon,
+ * and that may be confused with an expression.
+ * </p>
+ * @param semicolon the semicolon token kind
+ * @return true if statement is ambiguous, false otherwise
+ */
+ protected boolean isAmbiguousStatement(int semicolon) {
+ if (autoSemicolon) {
+ Token current = getToken(0);
+ Token next = getToken(1);
+ if (current != null && next != null && current.endLine != next.beginLine) {
+ // if the next token is on a different line, no ambiguity reported
+ return false;
+ }
+ }
+ return !getFeatures().supportsAmbiguousStatement();
+ }
+
/**
* Called by parser at end of node construction.
* <p>
diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlScriptParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlScriptParser.java
index e4ab6913..80277455 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlScriptParser.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlScriptParser.java
@@ -37,4 +37,5 @@ public interface JexlScriptParser {
* @throws JexlException if any error occurred during parsing
*/
ASTJexlScript parse(final JexlInfo info, final JexlFeatures features, final String src, final Scope scope);
+
}
diff --git a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
index caed1e89..5470bc01 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
+++ b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
@@ -49,6 +49,17 @@ import org.apache.commons.jexl3.internal.Scope;
public final class Parser extends JexlParser
{
+
+ /**
+ * Parses a JEXL source string and returns the corresponding AST.
+ * @param jexlInfo the JEXL info to use, may be null
+ * @param jexlFeatures the JEXL features to use
+ * @param jexlSrc the JEXL source string to parse
+ * @param jexlScope the scope to use for parsing
+ * @return the AST for the JEXL source string
+ * @throws JexlException.Tokenization if there is a tokenization error
+ * @throws JexlException.Parsing if there is a parsing error
+ */
public ASTJexlScript parse(JexlInfo jexlInfo, JexlFeatures jexlFeatures, String jexlSrc, Scope jexlScope) {
JexlFeatures previous = getFeatures();
try {
@@ -108,7 +119,7 @@ TOKEN_MGR_DECLS : {
| <"//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")? >
}
-<NEVER> TOKEN : /* Exception handling. */
+<DEFAULT> TOKEN : /* Exception handling. */
{
< THROW : "throw" >
| < TRY : "try" >
@@ -116,7 +127,7 @@ TOKEN_MGR_DECLS : {
| < FINALLY : "finally" >
}
-<NEVER> TOKEN : /* Type check. */
+<DEFAULT> TOKEN : /* Type check. */
{
< ISA : "instanceof" >
}
@@ -246,6 +257,7 @@ TOKEN_MGR_DECLS : {
| < SWITCH : "switch" >
| < CASE : "case" >
| < CASE_DEFAULT : "default" >
+ | < IMPORT : "import" >
}
@@ -364,7 +376,7 @@ ASTJexlScript JexlScript(Scope frame, JexlFeatures features) : {
{
pushUnit(jjtThis);
}
- ( LOOKAHEAD(<PRAGMA>) Pragma() | { controlPragmaAnywhere(); } Statement() )* <EOF>
+ (LOOKAHEAD(<IMPORT>) Import())* ( LOOKAHEAD(<PRAGMA>) Pragma() | { controlPragmaAnywhere(); } Statement() )* <EOF>
{
popUnit(jjtThis);
return jjtThis.script();
@@ -440,7 +452,7 @@ void FunctionStatement() #JexlLambda : {}
void ExpressionStatement() #void : {}
{
- Expression() (LOOKAHEAD(Expression(), { !getFeatures().supportsAmbiguousStatement() } ) Expression() #Ambiguous(1))* (LOOKAHEAD(1) <SEMICOL>)?
+ Expression() (LOOKAHEAD(Expression(), { isAmbiguousStatement(SEMICOL) } ) Expression() #Ambiguous(1))* (LOOKAHEAD(1) <SEMICOL>)*
}
@@ -487,14 +499,18 @@ void DoWhileStatement() : {}
<DO> { loopCount += 1; } (LOOKAHEAD(1) Block() | StatementNoVar()) <WHILE> <LPAREN> Expression() <RPAREN> { loopCount -= 1; }
}
-void ReturnStatement() : {}
+void ReturnStatement() : {
+ this.autoSemicolon = false;
+ }
{
- <RETURN> (LOOKAHEAD(2) ExpressionStatement() )?
+ <RETURN> (LOOKAHEAD(2) ExpressionStatement() )? { this.autoSemicolon = true; }
}
-void ThrowStatement() : {}
+void ThrowStatement() : {
+ this.autoSemicolon = false;
+ }
{
- <THROW> (LOOKAHEAD(2) ExpressionStatement() )?
+ <THROW> (LOOKAHEAD(2) ExpressionStatement() )? { this.autoSemicolon = true; }
}
void Continue() #Continue : {
@@ -580,6 +596,7 @@ void DeclareVar(boolean lexical, boolean constant) #Var :
{
t=<IDENTIFIER> { declareVariable(jjtThis, t, lexical, constant); }
}
+
void DeclareFunction() #Var :
{
Token t;
@@ -588,7 +605,6 @@ void DeclareFunction() #Var :
t=<IDENTIFIER> { declareFunction(jjtThis, t); }
}
-
void SwitchStatement() #SwitchStatement :
{
ASTSwitchStatement.Helper helper = new ASTSwitchStatement.Helper();
@@ -647,7 +663,7 @@ void SwitchExpressionCase(SwitchSet cases) #CaseExpression :
|
<CASE_DEFAULT> <LAMBDA>
)
- ( LOOKAHEAD(3) Block() | Expression())
+ ( LOOKAHEAD(3) Block() | Expression() (<SEMICOL>)?)
}
void ConstLiterals(List<Object> constants) #void :
@@ -661,9 +677,10 @@ void ConstLiterals(List<Object> constants) #void :
Object constLiteral() #void :
{
-Token s = null;
-Token v;
-Object result;
+ Token s = null;
+ Token v;
+ Object result;
+ LinkedList<String> lstr = new LinkedList<String>();
}
{
(
@@ -674,12 +691,23 @@ Object result;
| LOOKAHEAD(1) <FALSE> { result = false; }
| LOOKAHEAD(1) <NULL> { result = null; }
| LOOKAHEAD(1) <NAN_LITERAL> { result = Double.NaN; }
+ | LOOKAHEAD(1) propertyKey(lstr) { result = resolveConstant(stringify(lstr)); }
)
{
return result;
}
}
+void Import() #void :
+{
+ List<String> imports = new ArrayList<String>();
+}
+{
+ <IMPORT> propertyKey(imports) (LOOKAHEAD(1) <SEMICOL>)?
+ {
+ addImport(stringify(imports));
+ }
+}
void Pragma() #void :
{
@@ -687,15 +715,15 @@ void Pragma() #void :
Object value;
}
{
-<PRAGMA> pragmaKey(lstr) value=pragmaValue() { declarePragma(stringify(lstr), value); }
+<PRAGMA> propertyKey(lstr) value=pragmaValue() { declarePragma(stringify(lstr), value); }
}
-void pragmaKey(List<String> lstr) #void :
+void propertyKey(List<String> lstr) #void :
{
Token t;
}
{
- t=<IDENTIFIER> { lstr.add(t.image); } ( LOOKAHEAD(<DOT>) pragmaKey(lstr) )*
+ t=<IDENTIFIER> { lstr.add(t.image); } ( LOOKAHEAD(<DOT>) propertyKey(lstr) )*
|
<DOT> t=<DOT_IDENTIFIER> { lstr.add(t.image); }
}
@@ -712,7 +740,7 @@ Object result;
LOOKAHEAD(2) (s=<plus>|s=<minus>)? v=<INTEGER_LITERAL> { result = NumberParser.parseInteger(s, v); }
| LOOKAHEAD(2) (s=<plus>|s=<minus>)? v=<FLOAT_LITERAL> { result = NumberParser.parseDouble(s, v); }
| LOOKAHEAD(1) v=<STRING_LITERAL> { result = Parser.buildString(v.image, true); }
- | LOOKAHEAD(1) pragmaKey(lstr) { result = stringify(lstr); }
+ | LOOKAHEAD(1) propertyKey(lstr) { result = stringify(lstr); }
| LOOKAHEAD(1) <TRUE> { result = true; }
| LOOKAHEAD(1) <FALSE> { result = false; }
| LOOKAHEAD(1) <NULL> { result = null; }
@@ -1112,7 +1140,7 @@ void QualifiedIdentifier() #QualifiedIdentifier : {
LinkedList<String> lstr = new LinkedList<String>();
}
{
- pragmaKey(lstr) { jjtThis.setName(stringify(lstr));}
+ propertyKey(lstr) { jjtThis.setName(stringify(lstr));}
}
void Constructor() #ConstructorNode : {}
diff --git a/src/site/xdoc/relnotes35.xml b/src/site/xdoc/relnotes35.xml
index 5c9fbb3e..75c683a0 100644
--- a/src/site/xdoc/relnotes35.xml
+++ b/src/site/xdoc/relnotes35.xml
@@ -24,7 +24,7 @@
<body>
<section name="Compatibility with previous release">
<p>
- Version 3.5 is source and binary compatible with 3.4.
+ Version 3.6 is source and binary compatible with 3.5.
</p>
</section>
<section name="Compatibility with older releases (< 3.3, 2.x)">
@@ -49,7 +49,35 @@
or whether loops or side effects are accessible are part of your choice to make.
</p>
</section>
- <section name="What's new in 3.5:">
+
+ <section name="What is new in 3.6:">
+ <p>
+ JEXL 3.6 is a minor release that adds a few features and fixes some bugs.
+ It does not introduce any breaking change.
+ </p>
+ </section>
+ <section name="New Features in 3.6:">
+ <p>
+ <table>
+ <tr>
+ <td><a href="https://issues.apache.org/jira/browse/JEXL-440">JEXL-440:</a></td>
+ <td>Switch statement & expressions.</td>
+ </tr>
+ </table>
+ </p>
+ </section>
+ <section name="Bugs fixed in 3.6:">
+ <p>
+ <table>
+ <tr>
+ <td><a href="https://issues.apache.org/jira/browse/JEXL-437">JEXL-437:</a></td>
+ <td>Semicolons not actually optional between function calls on separate lines</td>
+ </tr>
+ </table>
+ </p>
+ </section>
+
+ <section name="What was new in 3.5:">
<p>
A feature that captures variables as references allowing side effect from a lambda to its
outer scope; this is mimicking JavaScript scoping rule (JEXL-426).
diff --git a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
index 7dbdb4b2..2e6102c1 100644
--- a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
+++ b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
@@ -765,7 +765,7 @@ public class ArithmeticTest extends JexlTestCase {
// JEXL-24: doubles with exponent
@Test
- public void test2DoubleLiterals() {
+ void test2DoubleLiterals() {
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
options.setStrictArithmetic(true);
@@ -782,7 +782,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testAddWithStringsLenient() {
+ void testAddWithStringsLenient() {
final JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(false)).create();
JexlScript script;
Object result;
@@ -820,7 +820,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testAddWithStringsStrict() {
+ void testAddWithStringsStrict() {
final JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(true)).create();
JexlScript script;
Object result;
@@ -859,7 +859,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testArithmeticPlus() throws Exception {
+ void testArithmeticPlus() {
final JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new ArithmeticPlus(false)).create();
final JexlContext jc = new EmptyTestContext();
runOverload(jexl, jc);
@@ -867,14 +867,14 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testArithmeticPlusNoCache() {
+ void testArithmeticPlusNoCache() {
final JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new ArithmeticPlus(false)).create();
final JexlContext jc = new EmptyTestContext();
runOverload(jexl, jc);
}
@Test
- public void testAtomicBoolean() {
+ void testAtomicBoolean() {
// in a condition
JexlScript e = JEXL.createScript("if (x) 1 else 2;", "x");
final JexlArithmetic jexla = JEXL.getArithmetic();
@@ -946,7 +946,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testBigDecimal() throws Exception {
+ void testBigDecimal() throws Exception {
asserter.setVariable("left", new BigDecimal(2));
asserter.setVariable("right", new BigDecimal(6));
asserter.assertExpression("left + right", new BigDecimal(8));
@@ -957,7 +957,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testBigdOp() {
+ void testBigdOp() {
final BigDecimal sevendot475 = new BigDecimal("7.475");
final BigDecimal SO = new BigDecimal("325");
final JexlContext jc = new MapContext();
@@ -971,7 +971,7 @@ public class ArithmeticTest extends JexlTestCase {
// JEXL-24: big decimals with exponent
@Test
- public void testBigExponentLiterals() {
+ void testBigExponentLiterals() {
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
options.setStrictArithmetic(true);
@@ -986,7 +986,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testBigInteger() throws Exception {
+ void testBigInteger() throws Exception {
asserter.setVariable("left", new BigInteger("2"));
asserter.setVariable("right", new BigInteger("6"));
asserter.assertExpression("left + right", new BigInteger("8"));
@@ -998,7 +998,7 @@ public class ArithmeticTest extends JexlTestCase {
// JEXL-24: big integers and big decimals
@Test
- public void testBigLiterals() {
+ void testBigLiterals() {
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
options.setStrictArithmetic(true);
@@ -1012,7 +1012,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testBigLiteralValue() {
+ void testBigLiteralValue() {
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
options.setStrictArithmetic(true);
@@ -1025,7 +1025,7 @@ public class ArithmeticTest extends JexlTestCase {
* test some simple mathematical calculations
*/
@Test
- public void testCalculations() throws Exception {
+ void testCalculations() throws Exception {
asserter.setStrict(true, false);
/*
* test new null coersion
@@ -1068,7 +1068,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCoerceBigDecimal() {
+ void testCoerceBigDecimal() {
final JexlArithmetic ja = JEXL.getArithmetic();
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
@@ -1098,7 +1098,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCoerceBigInteger() {
+ void testCoerceBigInteger() {
final JexlArithmetic ja = JEXL.getArithmetic();
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
@@ -1117,7 +1117,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCoerceDouble() {
+ void testCoerceDouble() {
final JexlArithmetic ja = JEXL.getArithmetic();
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
@@ -1136,7 +1136,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCoerceInteger() {
+ void testCoerceInteger() {
final JexlArithmetic ja = JEXL.getArithmetic();
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
@@ -1155,7 +1155,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCoerceLong() {
+ void testCoerceLong() {
final JexlArithmetic ja = JEXL.getArithmetic();
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
@@ -1174,7 +1174,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCoercions() throws Exception {
+ void testCoercions() throws Exception {
asserter.assertExpression("1", Integer.valueOf(1)); // numerics default to Integer
asserter.assertExpression("5L", Long.valueOf(5));
@@ -1206,7 +1206,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testCompare() {
+ void testCompare() {
// JEXL doesn't support more than one operator in the same expression, for example: 1 == 1 == 1
final Object[] EXPRESSIONS = {
// Basic compare
@@ -1287,7 +1287,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testDivClass() {
+ void testDivClass() {
final JexlEngine jexl = new JexlBuilder().create();
final JexlContext jc = new MapContext();
final Object ra = jexl.createExpression("463.0d / 0.1").evaluate(jc);
@@ -1304,7 +1304,7 @@ public class ArithmeticTest extends JexlTestCase {
* if not silent, all arith exception throw
*/
@Test
- public void testDivideByZero() throws Exception {
+ void testDivideByZero() throws Exception {
final Map<String, Object> vars = new HashMap<>();
final JexlEvalContext context = new JexlEvalContext(vars);
final JexlOptions options = context.getEngineOptions();
@@ -1375,7 +1375,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testDivideEdges() {
+ void testDivideEdges() {
assertNullOperand(() -> jexla.divide(null, null));
assertEquals(0, jexlb.divide(null, null));
assertNullOperand(() -> jexla.divide(null, null));
@@ -1389,7 +1389,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testEmpty() throws Exception {
+ void testEmpty() throws Exception {
final Object[] SCRIPTS = {
"var x = null; log('x = %s', x);", 0,
"var x = 'abc'; log('x = %s', x);", 1,
@@ -1426,7 +1426,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testEmptyDouble() {
+ void testEmptyDouble() {
Object x;
x = JEXL.createScript("4294967296.d").execute(null);
assertEquals(4294967296.0d, (Double) x, EPSILON);
@@ -1443,7 +1443,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testEmptyFloat() {
+ void testEmptyFloat() {
Object x;
x = JEXL.createScript("4294967296.f").execute(null);
assertEquals(4294967296.0f, (Float) x, EPSILON);
@@ -1459,7 +1459,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testEmptyLong() {
+ void testEmptyLong() {
Object x;
x = JEXL.createScript("new('java.lang.Long', 4294967296)").execute(null);
assertEquals(4294967296L, ((Long) x).longValue());
@@ -1478,7 +1478,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testFailAllOperators() {
+ void testFailAllOperators() {
// @formatter:off
final String[] scripts = {
"(x, y)->{ x < y }",
@@ -1527,7 +1527,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testInfiniteArithmetic() throws Exception {
+ void testInfiniteArithmetic() {
final Map<String, Object> ns = new HashMap<>();
ns.put("math", Math.class);
final JexlEngine jexl = new JexlBuilder().arithmetic(new Arithmetic132()).namespaces(ns).create();
@@ -1555,20 +1555,20 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testInstanceOf0() throws Exception {
+ void testInstanceOf0() {
final JexlEngine jexl = new JexlBuilder().strict(true).safe(false).create();
final JexlContext ctxt = new InstanceofContext();
runInstanceof(jexl, ctxt);
}
@Test
- public void testInstanceOf1() throws Exception {
+ void testInstanceOf1() {
final JexlEngine jexl = new JexlBuilder().strict(true).safe(false).imports("java.lang").create();
runInstanceof(jexl, null);
}
@Test
- public void testIntegerCoercionEdges() {
+ void testIntegerCoercionEdges() {
assertNullOperand(() -> jexla.toBoolean(null));
assertTrue(jexla.toBoolean(date));
// int coercions
@@ -1593,7 +1593,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testIsFloatingPointPattern() {
+ void testIsFloatingPointPattern() {
final JexlArithmetic ja = new JexlArithmetic(true);
assertFalse(ja.isFloatingPointNumber("floating point"));
@@ -1634,7 +1634,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testJexl173() {
+ void testJexl173() {
final JexlEngine jexl = new JexlBuilder().create();
final JexlContext jc = new MapContext();
final Callable173 c173 = new Callable173();
@@ -1648,7 +1648,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testLeftNullOperand() throws Exception {
+ void testLeftNullOperand() throws Exception {
asserter.setVariable("left", null);
asserter.setVariable("right", Integer.valueOf(8));
asserter.setStrict(true);
@@ -1667,7 +1667,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testLeftNullOperand2() throws Exception {
+ void testLeftNullOperand2() throws Exception {
asserter.setVariable("x.left", null);
asserter.setVariable("right", Integer.valueOf(8));
asserter.setStrict(true);
@@ -1687,7 +1687,7 @@ public class ArithmeticTest extends JexlTestCase {
// JEXL-24: long integers (and doubles)
@Test
- public void testLongLiterals() {
+ void testLongLiterals() {
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
options.setStrictArithmetic(true);
@@ -1703,12 +1703,12 @@ public class ArithmeticTest extends JexlTestCase {
assertEquals(63.5d, ctxt.get("g"));
assertEquals(0x10, ctxt.get("h"));
assertEquals(010, ctxt.get("i")); // octal 010
- assertEquals(0x10L, ctxt.get("j")); // octal 010L
- assertEquals(010L, ctxt.get("k"));
+ assertEquals(0x10L, ctxt.get("j")); // hexa 010L
+ assertEquals(010L, ctxt.get("k")); // octal 010L
}
@Test
- public void testMinusClass() {
+ void testMinusClass() {
final JexlEngine jexl = new JexlBuilder().create();
final JexlContext jc = new MapContext();
final Object ra = jexl.createExpression("463.0d - 0.1").evaluate(jc);
@@ -1720,7 +1720,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testMinusMinusPostfix() throws Exception {
+ void testMinusMinusPostfix() throws Exception {
asserter.setVariable("aByte", Byte.valueOf((byte) 2));
asserter.setVariable("aShort", Short.valueOf((short) 3));
asserter.setVariable("anInteger", Integer.valueOf(4));
@@ -1753,7 +1753,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testMinusMinusPrefix() throws Exception {
+ void testMinusMinusPrefix() throws Exception {
asserter.setVariable("aByte", Byte.valueOf((byte) 2));
asserter.setVariable("aShort", Short.valueOf((short) 3));
asserter.setVariable("anInteger", Integer.valueOf(4));
@@ -1777,7 +1777,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testModEdge() {
+ void testModEdge() {
assertNullOperand(() -> jexla.mod(null, null));
assertEquals(0, jexlb.mod(null, null));
assertArithmeticException(() -> jexla.mod(1, 0));
@@ -1793,7 +1793,7 @@ public class ArithmeticTest extends JexlTestCase {
* JEXL-156.
*/
@Test
- public void testMultClass(){
+ void testMultClass(){
final JexlEngine jexl = new JexlBuilder().create();
final JexlContext jc = new MapContext();
final Object ra = jexl.createExpression("463.0d * 0.1").evaluate(jc);
@@ -1805,7 +1805,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testNaN() {
+ void testNaN() {
final Map<String, Object> ns = new HashMap<>();
ns.put("double", Double.class);
final JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
@@ -1826,7 +1826,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testNarrowBigDecimal() throws Exception {
+ void testNarrowBigDecimal() throws Exception {
final List<String> ls = Arrays.asList("zero", "one", "two");
asserter.setVariable("list", ls);
asserter.assertExpression("a -> list.get(a)", "zero", BigDecimal.ZERO);
@@ -1844,7 +1844,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testNarrowBigInteger() throws Exception {
+ void testNarrowBigInteger() throws Exception {
final List<String> ls = Arrays.asList("zero", "one", "two");
asserter.setVariable("list",ls);
asserter.assertExpression("a -> list.get(a)", "zero", BigInteger.ZERO);
@@ -1861,10 +1861,10 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testNullArgs() {
+ void testNullArgs() {
final JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(true) {
@Override public boolean isStrict(final JexlOperator op) {
- return JexlOperator.ADD == op? false: super.isStrict(op);
+ return JexlOperator.ADD != op && super.isStrict(op);
}
}).create();
final JexlScript script = jexl.createScript("'1.2' + x ", "x");
@@ -1873,13 +1873,13 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testNullOperand() throws Exception {
+ void testNullOperand() throws Exception {
asserter.setVariable("right", null);
asserter.failExpression("~right", ".*null.*");
}
@Test
- public void testNullOperands() throws Exception {
+ void testNullOperands() throws Exception {
asserter.setVariable("left", null);
asserter.setVariable("right", null);
asserter.failExpression("left + right", ".*null.*");
@@ -1893,7 +1893,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testOperatorsEdges() {
+ void testOperatorsEdges() {
assertNullOperand(() -> jexla.multiply(null, null));
assertEquals(0, jexlb.multiply(null, null));
assertNullOperand(() -> jexla.add(null, null));
@@ -1914,7 +1914,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testOption() {
+ void testOption() {
final Map<String, Object> vars = new HashMap<>();
final JexlEvalContext context = new JexlEvalContext(vars);
final JexlOptions options = context.getEngineOptions();
@@ -1932,7 +1932,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testOverflows() throws Exception {
+ void testOverflows() throws Exception {
asserter.assertExpression("1 + 2147483647", Long.valueOf("2147483648"));
asserter.assertExpression("3 + " + (Long.MAX_VALUE - 2), BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE));
asserter.assertExpression("-2147483648 - 1", Long.valueOf("-2147483649"));
@@ -1945,7 +1945,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testPlusClass() {
+ void testPlusClass() {
final JexlEngine jexl = new JexlBuilder().create();
final JexlContext jc = new MapContext();
final Object ra = jexl.createExpression("463.0d + 0.1").evaluate(jc);
@@ -1957,7 +1957,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testPlusPlusPostfix() throws Exception {
+ void testPlusPlusPostfix() throws Exception {
asserter.setVariable("aByte", Byte.valueOf((byte) 0));
asserter.setVariable("aShort", Short.valueOf((short) 1));
asserter.setVariable("anInteger", Integer.valueOf(2));
@@ -1990,7 +1990,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testPlusPlusPrefix() throws Exception {
+ void testPlusPlusPrefix() throws Exception {
asserter.setVariable("aByte", Byte.valueOf((byte) 0));
asserter.setVariable("aShort", Short.valueOf((short) 1));
asserter.setVariable("anInteger", Integer.valueOf(2));
@@ -2014,7 +2014,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testRealCoercionEdges() throws Exception {
+ void testRealCoercionEdges() throws Exception {
assertNullOperand(() -> jexla.toDouble(null));
assertEquals(0.0d, jexlb.toDouble(null), EPSILON);
assertEquals(32.0d, jexlb.toDouble((char) 32), EPSILON);
@@ -2045,7 +2045,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testRightNullOperand() throws Exception {
+ void testRightNullOperand() throws Exception {
asserter.setVariable("left", Integer.valueOf(9));
asserter.setVariable("right", null);
asserter.failExpression("left + right", ".*null.*");
@@ -2063,7 +2063,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testRightNullOperand2() throws Exception {
+ void testRightNullOperand2() throws Exception {
asserter.setVariable("left", Integer.valueOf(9));
asserter.setVariable("y.right", null);
asserter.failExpression("left + y.right", ".*null.*");
@@ -2084,7 +2084,7 @@ public class ArithmeticTest extends JexlTestCase {
* test some simple mathematical calculations
*/
@Test
- public void testUnaryMinus() throws Exception {
+ void testUnaryMinus() throws Exception {
asserter.setVariable("aByte", Byte.valueOf((byte) 1));
asserter.setVariable("aShort", Short.valueOf((short) 2));
asserter.setVariable("anInteger", Integer.valueOf(3));
@@ -2110,7 +2110,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testUnaryopsEdges() {
+ void testUnaryopsEdges() {
assertArithmeticException(() -> jexla.positivize(date));
assertNullOperand(() -> jexla.positivize(null));
assertNull(jexlb.positivize(null));
@@ -2131,7 +2131,7 @@ public class ArithmeticTest extends JexlTestCase {
* test some simple mathematical calculations
*/
@Test
- public void testUnaryPlus() throws Exception {
+ void testUnaryPlus() throws Exception {
asserter.setVariable("aByte", Byte.valueOf((byte) 1));
asserter.setVariable("aShort", Short.valueOf((short) 2));
asserter.setVariable("anInteger", Integer.valueOf(3));
@@ -2157,7 +2157,7 @@ public class ArithmeticTest extends JexlTestCase {
}
@Test
- public void testUndefinedVar() throws Exception {
+ void testUndefinedVar() throws Exception {
asserter.failExpression("objects[1].status", ".*variable 'objects' is undefined.*");
}
@@ -2165,7 +2165,7 @@ public class ArithmeticTest extends JexlTestCase {
* Inspired by JEXL-16{1,2}.
*/
@Test
- public void testXmlArithmetic() throws Exception {
+ void testXmlArithmetic() throws Exception {
Document xml;
Node x;
Boolean empty;
diff --git a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
index 161a3660..58abf7e0 100644
--- a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
+++ b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
@@ -59,7 +59,7 @@ public class FeaturesTest extends JexlTestCase {
* @param scripts the scripts
* @throws Exception
*/
- private void checkFeature(final JexlFeatures features, final String[] scripts) throws Exception {
+ private void checkFeature(final JexlFeatures features, final String[] scripts) {
for (final String script : scripts) {
final JexlScript ctl = JEXL.createScript(script);
assertNotNull(ctl);
@@ -108,12 +108,12 @@ public class FeaturesTest extends JexlTestCase {
"3 ge 2"
};
for(final String src : cmpNameScripts) {
- assertThrows(JexlException.Ambiguous.class, () -> jexl.createScript(src));
+ assertThrows(JexlException.Ambiguous.class, () -> jexl.createScript(src), src);
}
}
@Test
- void testAnnotations() throws Exception {
+ void testAnnotations() {
final JexlFeatures f = new JexlFeatures().annotation(false);
final String[] scripts = {
"@synchronized(2) { return 42; }",
@@ -123,7 +123,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testArrayRefs() throws Exception {
+ void testArrayRefs() {
final JexlFeatures f = new JexlFeatures().arrayReferenceExpr(false);
final String[] scripts = {
@@ -145,7 +145,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testConstCapture() throws Exception {
+ void testConstCapture() {
final JexlFeatures f = new JexlFeatures().constCapture(true);
final String[] scripts = {
"let x = 0; const f = y -> x += y; f(42)",
@@ -202,7 +202,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testMethodCalls() throws Exception {
+ void testMethodCalls() {
final JexlFeatures f = new JexlFeatures().methodCall(false);
final String[] scripts = {
"x.y(z)",
@@ -221,7 +221,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testMixedFeatures() throws Exception {
+ void testMixedFeatures() {
// no new, no local, no lambda, no loops, no-side effects
final JexlFeatures f = new JexlFeatures()
.newInstance(false)
@@ -241,7 +241,7 @@ public class FeaturesTest extends JexlTestCase {
checkFeature(f, scripts);
}
@Test
- void testNoComparatorNames() throws Exception {
+ void testNoComparatorNames() {
final JexlFeatures f = new JexlFeatures().comparatorNames(false);
final String[] scripts = {
"1 eq 1",
@@ -255,7 +255,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testNoLambda() throws Exception {
+ void testNoLambda() {
final JexlFeatures f = new JexlFeatures().lambda(false);
final String[] scripts = {
"var x = ()->{ return 0 };",
@@ -269,7 +269,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testNoLocals() throws Exception {
+ void testNoLocals() {
final JexlFeatures f = new JexlFeatures().localVar(false);
final String[] scripts = {
"var x = 0;",
@@ -279,7 +279,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testNoLoop() throws Exception {
+ void testNoLoop() {
final JexlFeatures f = new JexlFeatures().loops(false);
final String[] scripts = {
"while(true);",
@@ -288,7 +288,7 @@ public class FeaturesTest extends JexlTestCase {
checkFeature(f, scripts);
}
@Test
- void testNoNew() throws Exception {
+ void testNoNew() {
final JexlFeatures f = new JexlFeatures().newInstance(false);
final String[] scripts = {
"return new(clazz);",
@@ -298,7 +298,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testNoScript() throws Exception {
+ void testNoScript() {
final JexlFeatures f = new JexlFeatures().script(false);
assertTrue(f.supportsExpression());
final String[] scripts = {
@@ -311,7 +311,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testNoSideEffects() throws Exception {
+ void testNoSideEffects() {
final JexlFeatures f = new JexlFeatures().sideEffect(false);
final String[] scripts = {
"x = 1",
@@ -335,7 +335,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testNoSideEffectsGlobal() throws Exception {
+ void testNoSideEffectsGlobal() {
final JexlFeatures f = new JexlFeatures().sideEffectGlobal(false);
final String[] scripts = {
"x = 1",
@@ -366,7 +366,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testPragma() throws Exception {
+ void testPragma() {
final JexlFeatures f = new JexlFeatures().pragma(false);
final String[] scripts = {
"#pragma foo 42",
@@ -376,7 +376,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testPragmaAnywhere() throws Exception {
+ void testPragmaAnywhere() {
final JexlFeatures f = new JexlFeatures().pragmaAnywhere(false);
final String[] scripts = {
"var x = 3;\n#pragma foo 42",
@@ -385,7 +385,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testReservedVars() throws Exception {
+ void testReservedVars() {
final JexlFeatures f = new JexlFeatures().reservedNames(Arrays.asList("foo", "bar"));
final String[] scripts = {
"var foo = 0;",
@@ -402,7 +402,7 @@ public class FeaturesTest extends JexlTestCase {
}
@Test
- void testStructuredLiterals() throws Exception {
+ void testStructuredLiterals() {
final JexlFeatures f = new JexlFeatures().structuredLiteral(false);
final String[] scripts = {
"{1, 2, 3}",
diff --git a/src/test/java/org/apache/commons/jexl3/Issues200Test.java b/src/test/java/org/apache/commons/jexl3/Issues200Test.java
index 20c84077..75ee6fc5 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues200Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues200Test.java
@@ -219,7 +219,7 @@ public class Issues200Test extends JexlTestCase {
public Object call(final Collection<?> c, final Number n) {
if (c instanceof List) {
- return ((List) c).get(n.intValue());
+ return ((List<?>) c).get(n.intValue());
}
return nth(c, n.intValue());
}
@@ -258,13 +258,13 @@ public class Issues200Test extends JexlTestCase {
@BeforeEach
@Override
- public void setUp() throws Exception {
+ public void setUp() {
// ensure jul logging is only error to avoid warning in silent mode
java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
}
@Test
- public void test200() throws Exception {
+ void test200() {
final JexlContext jc = new MapContext();
final Map<String, Object> funcs = new HashMap<>();
final Eval eval = new Eval();
@@ -278,7 +278,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test200b() throws Exception {
+ void test200b() {
final JexlContext jc = new MapContext();
final JexlEngine jexl = new JexlBuilder().create();
final JexlScript e = jexl.createScript("var x = 0; var f = (y)->{ x = y; }; f(42); x");
@@ -287,7 +287,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test209a() throws Exception {
+ void test209a() {
final JexlContext jc = new MapContext();
final JexlEngine jexl = new JexlBuilder().create();
final JexlScript e = jexl.createScript("var x = new('java.util.HashMap'); x.a = ()->{return 1}; x['a']()");
@@ -296,7 +296,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test209b() throws Exception {
+ void test209b() {
final JexlContext jc = new MapContext();
final JexlEngine jexl = new JexlBuilder().create();
final JexlScript e = jexl.createScript("var x = new('java.util.HashMap'); x['a'] = ()->{return 1}; x.a()");
@@ -305,7 +305,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test210() throws Exception {
+ void test210() {
final JexlContext jc = new MapContext();
jc.set("v210", new T210());
final JexlEngine jexl = new JexlBuilder().strict(false).silent(false).create();
@@ -316,7 +316,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test217() throws Exception {
+ void test217() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
jc.set("foo", new int[]{0, 1, 2, 42});
@@ -341,7 +341,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test221() throws Exception {
+ void test221() {
final JexlEvalContext jc = new JexlEvalContext();
final Map<String, Integer> map = new HashMap<>();
map.put("one", 1);
@@ -358,7 +358,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test224() throws Exception {
+ void test224() {
final List<String> a0 = Arrays.asList("one", "two");
final Set<String> a1 = new TreeSet<>(a0);
final JexlContext jc = new MapContext();
@@ -382,7 +382,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test225() throws Exception {
+ void test225() {
final Context225 df = new Context225();
final JexlEngine jexl = new JexlBuilder().create();
@@ -393,7 +393,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test230() throws Exception {
+ void test230() {
final JexlEngine jexl = new JexlBuilder().cache(4).create();
final JexlContext ctxt = new MapContext();
final int[] foo = {42};
@@ -412,7 +412,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test241() throws Exception {
+ void test241() {
ExecutorService pool;
final JexlScript script = new JexlBuilder().create().createScript("`${item}`");
@@ -429,7 +429,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test242() throws Exception {
+ void test242() {
final Double a = -40.05d;
final Double b = -8.01d;
final Double c = a + b;
@@ -444,13 +444,13 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test243a() throws Exception {
+ void test243a() {
final JexlEngine jexl = new JexlBuilder().cache(32).create();
final JexlScript script = jexl.createScript("while(true);");
assertThrows(JexlException.class, () -> jexl.createExpression("while(true);"), "expr do not allow 'while' statement");
}
@Test
- public void test245() throws Exception {
+ void test245() {
final MapContext ctx = new MapContext();
final Foo245 foo245 = new Foo245();
ctx.set("foo", foo245);
@@ -473,7 +473,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test256() throws Exception {
+ void test256() {
final MapContext ctx = new MapContext() {
@Override
public Object get(final String name) {
@@ -507,7 +507,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test265() throws Exception {
+ void test265() {
final JexlEngine jexl = new JexlBuilder().cache(4).create();
final JexlContext ctxt = new MapContext();
ctxt.set("x", 42);
@@ -526,7 +526,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test266() throws Exception {
+ void test266() {
Object result;
JexlScript script;
final JexlEngine jexl = new JexlBuilder().arithmetic(new Arithmetic266(true)).create();
@@ -554,7 +554,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test267() throws Exception {
+ void test267() {
Object result;
JexlScript script;
final JexlEngine jexl = new JexlBuilder().create();
@@ -574,7 +574,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test274() throws Exception {
+ void test274() {
JexlEngine jexl = new JexlBuilder().strict(true).safe(true).stackOverflow(5).create();
final JexlContext ctxt = new MapContext();
final JexlScript script = jexl.createScript("var f = (x)->{ x > 1? x * f(x - 1) : x }; f(a)", "a");
@@ -589,7 +589,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test275a() throws Exception {
+ void test275a() {
final JexlContext ctxt = new MapContext();
ctxt.set("out", System.out);
final JexlEngine jexl = new JexlBuilder().strict(true).safe(true).create();
@@ -599,7 +599,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test275b() throws Exception {
+ void test275b() {
final JexlContext ctxt = new MapContext();
// ctxt.set("out", System.out);
final JexlEngine jexl = new JexlBuilder().strict(true).safe(true).create();
@@ -609,7 +609,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test275c() throws Exception {
+ void test275c() {
final JexlContext ctxt = new MapContext();
// ctxt.set("out", System.out);
final JexlEngine jexl = new JexlBuilder().strict(true).safe(true).silent(true).create();
@@ -622,7 +622,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test275d() throws Exception {
+ void test275d() {
final JexlContext ctxt = new MapContext();
ctxt.set("out", System.out);
final JexlEngine jexl = new JexlBuilder().strict(true).safe(true).create();
@@ -632,7 +632,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test278() throws Exception {
+ void test278() {
// @formatter:off
final String[] srcs = {
"return union x143('arg',5,6) ",
@@ -653,7 +653,7 @@ public class Issues200Test extends JexlTestCase {
JexlScript jc;
for (int i = 0; i < srcs.length; ++i) {
final String src = srcs[i];
- final JexlException.Ambiguous xa = assertThrows(JexlException.Ambiguous.class, () -> jexl.createScript(src));
+ final JexlException.Ambiguous xa = assertThrows(JexlException.Ambiguous.class, () -> jexl.createScript(src), src);
final String str = xa.toString();
assertTrue(str.contains("143"));
final String clean = xa.tryCleanSource(src);
@@ -665,7 +665,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test279() throws Exception {
+ void test279() {
final Log logger = null; // LogFactory.getLog(Issues200Test.class);
Object result;
JexlScript script;
@@ -734,7 +734,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test279b() throws Exception {
+ void test279b() {
Object result;
JexlScript script;
final JexlContext ctxt = new Context279();
@@ -749,7 +749,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test285() throws Exception {
+ void test285() {
final List<String> out = new ArrayList<>(6);
final JexlContext ctxt = new MapContext();
ctxt.set("$out", out);
@@ -778,7 +778,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test285a() throws Exception {
+ void test285a() {
final List<String> out = new ArrayList<>(6);
final JexlContext ctxt = new MapContext();
ctxt.set("$out", out);
@@ -796,7 +796,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test285b() throws Exception {
+ void test285b() {
final List<String> out = new ArrayList<>(6);
final JexlContext ctxt = new MapContext();
ctxt.set("$out", out);
@@ -814,14 +814,14 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test286() {
+ void test286() {
final String s286 = "var x = 0; for(x : 1..2){}; return x";
final JexlEngine jexl = new JexlBuilder().strict(true).create();
assertEquals(2, jexl.createScript(s286).execute(null));
}
@Test
- public void test287() {
+ void test287() {
final JexlEvalContext ctxt = new JexlEvalContext();
final JexlOptions options = ctxt.getEngineOptions();
final JexlEngine jexl = new JexlBuilder().strict(true).create();
@@ -860,7 +860,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test289() {
+ void test289() {
final JexlContext ctxt = new MapContext();
final JexlEngine jexl = new JexlBuilder().strict(true).create();
String src;
@@ -873,7 +873,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test290a() throws Exception {
+ void test290a() {
Object result;
JexlScript script;
final String[] srcs = {
@@ -904,7 +904,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test290b() throws Exception {
+ void test290b() {
Object result;
JexlScript script;
final String[] srcs = {
@@ -920,7 +920,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test291() throws Exception {
+ void test291() {
final String str = "{1:'one'}[1]";
final JexlContext ctxt = new MapContext();
final JexlEngine jexl = new JexlBuilder().create();
@@ -937,7 +937,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void test298() throws Exception {
+ void test298() {
final Cls298 c298 = new Cls298();
final JexlContext ctxt = new MapContext();
final JexlEngine jexl = new JexlBuilder().create();
@@ -959,7 +959,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void testTemplate6565a() throws Exception {
+ void testTemplate6565a() {
final JexlEngine jexl = new JexlBuilder().create();
final JxltEngine jexlt = jexl.createJxltEngine();
final String source =
@@ -982,7 +982,7 @@ public class Issues200Test extends JexlTestCase {
}
@Test
- public void testTemplate6565b() throws Exception {
+ void testTemplate6565b() {
final JexlEngine jexl = new JexlBuilder().create();
final JxltEngine jexlt = jexl.createJxltEngine();
final String source =
diff --git a/src/test/java/org/apache/commons/jexl3/Issues400Test.java b/src/test/java/org/apache/commons/jexl3/Issues400Test.java
index 8a969b2d..f81bda42 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues400Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues400Test.java
@@ -614,6 +614,45 @@ public class Issues400Test {
}
}
+ @Test
+ void test437a() {
+ JexlEngine jexl = new JexlBuilder().create();
+ final String src = "let values = [...]\n"
+ + "function append(const value) {\n"
+ + " values.add(value)\n"
+ + "}\n"
+ + "\n"
+ + "append(1)\n"
+ + "append(2)\n"
+ + "return values ";
+ final JexlScript script = jexl.createScript(src);
+ assertNotNull(script);
+ final Object result = script.execute(null);
+ assertInstanceOf(List.class, result);
+ List<?> values = (List<?>) result;
+ assertEquals(2, values.size());
+ }
+
+ @Test
+ void test437b() {
+ JexlFeatures features = JexlFeatures.createDefault().ambiguousStatement(true);
+ assertTrue(features.supportsAmbiguousStatement());
+ JexlEngine jexl = new JexlBuilder().features(features).create();
+ final String src = "let values = [...]"
+ + "function append(const value) {"
+ + " values.add(value)"
+ + "}"
+ + "append(1)"
+ + "append(2)"
+ + "return values ";
+ final JexlScript script = jexl.createScript(src);
+ assertNotNull(script);
+ final Object result = script.execute(null);
+ assertInstanceOf(List.class, result);
+ List<?> values = (List<?>) result;
+ assertEquals(2, values.size());
+ }
+
/** The set of characters that may be followed by a '='.*/
static final char[] EQ_FRIEND;
static {
@@ -729,11 +768,10 @@ public class Issues400Test {
@Test
void test440a() {
- JexlFeatures f = JexlFeatures.createDefault();
- f.setAmbiguousStatement(true);
+ JexlFeatures f = JexlFeatures.createDefault().ambiguousStatement(true);
JexlEngine jexl = new JexlBuilder().features(f).safe(false).strict(true).create();
- String src =
-"let y = switch (x) { case 10,11 -> 3 case 20, 21 -> 4\ndefault -> { let z = 4; z + x } } y";
+ String src = "let y = switch (x) { case 10,11 -> 3 case 20, 21 -> 4\n" +
+ "default -> { let z = 4; z + x } } y";
JexlScript script = jexl.createScript(src, "x");
assertNotNull(script);
String dbgStr = script.getParsedText();
@@ -749,8 +787,7 @@ public class Issues400Test {
Assertions.assertEquals(4, result);
result = script.execute(null, 38);
Assertions.assertEquals(42, result);
- src =
- "let y = switch (x) { case 10,11 -> break; case 20, 21 -> 4 } y";
+ src = "let y = switch (x) { case 10,11 -> break; case 20, 21 -> 4; } y";
try {
script = jexl.createScript(src, "x");
fail("should not be able to create script with break in switch");
@@ -780,4 +817,25 @@ public class Issues400Test {
result = script.execute(null, 38);
Assertions.assertEquals(42, result);
}
+
+ public enum Scope440 {
+ UNDEFINED, UNDECLARED, GLOBAL, LOCAL, THIS, SUPER;
+ }
+
+ @Test
+ void test440c() {
+ JexlEngine jexl = new JexlBuilder().loader(getClass().getClassLoader()).imports(this.getClass().getName()).create();
+ final String src = "let s = switch (x) { case Scope440.UNDEFINED -> 'undefined'; case Scope440.THIS -> 'this'; default -> 'OTHER'; } s";
+ final JexlScript script = jexl.createScript(src, "x");
+ assertNotNull(script);
+ String dbgStr = script.getParsedText();
+ assertNotNull(dbgStr);
+
+ Object result = script.execute(null, Scope440.UNDEFINED);
+ Assertions.assertEquals("undefined", result);
+ result = script.execute(null, Scope440.THIS);
+ Assertions.assertEquals("this", result);
+ result = script.execute(null, 21);
+ Assertions.assertEquals("OTHER", result);
+ }
}
diff --git a/src/test/java/org/apache/commons/jexl3/JexlTest.java b/src/test/java/org/apache/commons/jexl3/JexlTest.java
index f3f16d43..baa66380 100644
--- a/src/test/java/org/apache/commons/jexl3/JexlTest.java
+++ b/src/test/java/org/apache/commons/jexl3/JexlTest.java
@@ -92,14 +92,14 @@ public final class JexlTest extends JexlTestCase {
* Asserts that the given expression returns the given value when applied to the
* given context
*/
- protected void assertExpression(final JexlContext jc, final String expression, final Object expected) throws Exception {
+ protected void assertExpression(final JexlContext jc, final String expression, final Object expected) {
final JexlExpression e = JEXL.createExpression(expression);
final Object actual = e.evaluate(jc);
assertEquals(expected, actual, expression);
}
@Test
- public void testAntPropertiesWithMethods() throws Exception {
+ public void testAntPropertiesWithMethods() {
final JexlContext jc = new MapContext();
final String value = "Stinky Cheese";
jc.set("maven.bob.food", value);
@@ -116,7 +116,7 @@ public final class JexlTest extends JexlTestCase {
@SuppressWarnings("boxing")
@Test
- public void testArray() throws Exception {
+ public void testArray() {
final int[] array = {100, 101, 102};
final JexlEngine jexl = JEXL;
final JexlContext jc = new MapContext();
@@ -139,7 +139,7 @@ public final class JexlTest extends JexlTestCase {
* @throws Exception
*/
@Test
- public void testAssignment() throws Exception {
+ public void testAssignment() {
final JexlContext jc = new MapContext();
jc.set("aString", "Hello");
final Foo foo = new Foo();
@@ -161,7 +161,7 @@ public final class JexlTest extends JexlTestCase {
* @throws Exception on errors
*/
@Test
- public void testBadParse() throws Exception {
+ public void testBadParse() {
assertThrows(JexlException.class, () -> assertExpression(new MapContext(), "empty()", null));
}
@@ -169,7 +169,7 @@ public final class JexlTest extends JexlTestCase {
* test some blank strings
*/
@Test
- public void testBlankStrings() throws Exception {
+ public void testBlankStrings() {
final JexlContext jc = new MapContext();
jc.set("bar", "");
@@ -180,7 +180,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testBoolean() throws Exception {
+ public void testBoolean() {
final JexlContext jc = new MapContext();
jc.set("foo", new Foo());
jc.set("a", Boolean.TRUE);
@@ -199,7 +199,7 @@ public final class JexlTest extends JexlTestCase {
* @throws Exception if there are errors
*/
@Test
- public void testBooleanShortCircuitAnd() throws Exception {
+ public void testBooleanShortCircuitAnd() {
// handle false for the left arg of 'and'
Foo tester = new Foo();
final JexlContext jc = new MapContext();
@@ -221,7 +221,7 @@ public final class JexlTest extends JexlTestCase {
* @throws Exception if there are errors
*/
@Test
- public void testBooleanShortCircuitOr() throws Exception {
+ public void testBooleanShortCircuitOr() {
// handle false for the left arg of 'or'
Foo tester = new Foo();
final JexlContext jc = new MapContext();
@@ -242,7 +242,7 @@ public final class JexlTest extends JexlTestCase {
* test some simple mathematical calculations
*/
@Test
- public void testCalculations() throws Exception {
+ public void testCalculations() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
options.setStrict(false);
@@ -270,7 +270,7 @@ public final class JexlTest extends JexlTestCase {
* Attempts to recreate bug https://jira.werken.com/ViewIssue.jspa?key=JELLY-8
*/
@Test
- public void testCharAtBug() throws Exception {
+ public void testCharAtBug() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
options.setSilent(true);
@@ -284,7 +284,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testCoercionWithComparisionOperators() throws Exception {
+ public void testCoercionWithComparisionOperators() {
final JexlContext jc = new MapContext();
assertExpression(jc, "'2' > 1", Boolean.TRUE);
@@ -307,7 +307,7 @@ public final class JexlTest extends JexlTestCase {
* @throws Exception
*/
@Test
- public void testComment() throws Exception {
+ public void testComment() {
assertExpression(new MapContext(), "## double or nothing\n 1 + 1", Integer.valueOf("2"));
}
@@ -315,7 +315,7 @@ public final class JexlTest extends JexlTestCase {
* test some simple conditions
*/
@Test
- public void testComparisons() throws Exception {
+ public void testComparisons() {
final JexlContext jc = new MapContext();
jc.set("foo", "the quick and lazy fox");
@@ -328,7 +328,7 @@ public final class JexlTest extends JexlTestCase {
* test some simple conditions
*/
@Test
- public void testConditions() throws Exception {
+ public void testConditions() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
jc.set("foo", Integer.valueOf(2));
@@ -375,7 +375,7 @@ public final class JexlTest extends JexlTestCase {
@SuppressWarnings("boxing")
@Test
- public void testDuck() throws Exception {
+ public void testDuck() {
final JexlEngine jexl = JEXL;
final JexlContext jc = new MapContext();
jc.set("duck", new Duck());
@@ -402,7 +402,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testEmpty() throws Exception {
+ public void testEmpty() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
options.setStrict(false);
@@ -427,7 +427,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testEmptyDottedVariableName() throws Exception {
+ public void testEmptyDottedVariableName() {
final JexlContext jc = new MapContext();
jc.set("this.is.a.test", "");
@@ -436,7 +436,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testEmptySubListOfMap() throws Exception {
+ public void testEmptySubListOfMap() {
final JexlContext jc = new MapContext();
final Map<String, ArrayList<?>> m = new HashMap<>();
m.put("aList", new ArrayList<>());
@@ -447,7 +447,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testExpression() throws Exception {
+ public void testExpression() {
final JexlContext jc = new MapContext();
jc.set("foo", new Foo());
jc.set("a", Boolean.TRUE);
@@ -510,7 +510,7 @@ public final class JexlTest extends JexlTestCase {
* test the use of an int based property
*/
@Test
- public void testIntProperty() throws Exception {
+ public void testIntProperty() {
final Foo foo = new Foo();
// lets check the square function first.
@@ -529,7 +529,7 @@ public final class JexlTest extends JexlTestCase {
* test some blank strings
*/
@Test
- public void testLogicExpressions() throws Exception {
+ public void testLogicExpressions() {
final JexlContext jc = new MapContext();
jc.set("foo", "abc");
jc.set("bar", "def");
@@ -549,7 +549,7 @@ public final class JexlTest extends JexlTestCase {
* test the use of dot notation to lookup map entries
*/
@Test
- public void testMapDot() throws Exception {
+ public void testMapDot() {
final Map<String, String> foo = new HashMap<>();
foo.put("bar", "123");
@@ -563,7 +563,7 @@ public final class JexlTest extends JexlTestCase {
* test the -1 comparison bug
*/
@Test
- public void testNegativeIntComparison() throws Exception {
+ public void testNegativeIntComparison() {
final JexlContext jc = new MapContext();
final Foo foo = new Foo();
jc.set("foo", foo);
@@ -577,7 +577,7 @@ public final class JexlTest extends JexlTestCase {
* test the new function e.g constructor invocation
*/
@Test
- public void testNew() throws Exception {
+ public void testNew() {
final JexlContext jc = new MapContext();
jc.set("double", Double.class);
jc.set("foo", "org.apache.commons.jexl3.Foo");
@@ -595,8 +595,8 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testNewImports() throws Exception {
- final JexlEngine jexl = new JexlBuilder().imports("not a package", "java.lang", "java.util").create();
+ public void testNewImports() {
+ final JexlEngine jexl = new JexlBuilder().imports("java.lang", "java.util").create();
JexlExpression expr;
Object result;
expr = jexl.createExpression("new LinkedList([1,2,3,...])");
@@ -608,7 +608,7 @@ public final class JexlTest extends JexlTestCase {
* test some simple conditions
*/
@Test
- public void testNotConditions() throws Exception {
+ public void testNotConditions() {
final JexlContext jc = new MapContext();
final Foo foo = new Foo();
@@ -640,7 +640,7 @@ public final class JexlTest extends JexlTestCase {
* test some simple conditions
*/
@Test
- public void testNotConditionsWithDots() throws Exception {
+ public void testNotConditionsWithDots() {
final JexlContext jc = new MapContext();
jc.set("x.a", Boolean.TRUE);
@@ -655,7 +655,7 @@ public final class JexlTest extends JexlTestCase {
* test some null conditions
*/
@Test
- public void testNull() throws Exception {
+ public void testNull() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
options.setStrict(false);
@@ -674,7 +674,7 @@ public final class JexlTest extends JexlTestCase {
* test a simple property expression
*/
@Test
- public void testProperty() throws Exception {
+ public void testProperty() {
/*
* tests a simple property expression
*/
@@ -690,7 +690,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testSize() throws Exception {
+ public void testSize() {
final JexlEvalContext jc = new JexlEvalContext();
final JexlOptions options = jc.getEngineOptions();
options.setStrict(false);
@@ -744,7 +744,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testSizeAsProperty() throws Exception {
+ public void testSizeAsProperty() {
final JexlContext jc = new MapContext();
final Map<String, Object> map = new HashMap<>();
map.put("size", "cheese");
@@ -766,7 +766,7 @@ public final class JexlTest extends JexlTestCase {
* @throws Exception
*/
@Test
- public void testStringConcatenation() throws Exception {
+ public void testStringConcatenation() {
final JexlContext jc = new MapContext();
jc.set("first", "Hello");
jc.set("second", "World");
@@ -774,7 +774,7 @@ public final class JexlTest extends JexlTestCase {
}
@Test
- public void testStringLit() throws Exception {
+ public void testStringLit() {
/*
* tests a simple property expression
*/
@@ -787,7 +787,7 @@ public final class JexlTest extends JexlTestCase {
* Tests string literals
*/
@Test
- public void testStringLiterals() throws Exception {
+ public void testStringLiterals() {
final JexlContext jc = new MapContext();
jc.set("foo", "bar");
@@ -799,21 +799,21 @@ public final class JexlTest extends JexlTestCase {
* test quoting in strings
*/
@Test
- public void testStringQuoting() throws Exception {
+ public void testStringQuoting() {
final JexlContext jc = new MapContext();
assertExpression(jc, "'\"Hello\"'", "\"Hello\"");
assertExpression(jc, "\"I'm testing\"", "I'm testing");
}
@Test
- public void testToString() throws Exception {
+ public void testToString() {
final String code = "abcd";
final JexlExpression expr = JEXL.createExpression(code);
assertEquals(code, expr.toString(), "Bad expression value");
}
@Test
- public void testUnicodeSupport() throws Exception {
+ public void testUnicodeSupport() {
final JexlContext jc = new MapContext();
assertExpression(jc, "'x' == '\\u0032?ytkownik'", Boolean.FALSE);
assertExpression(jc, "'c:\\some\\windows\\path'", "c:\\some\\windows\\path");
@@ -826,7 +826,7 @@ public final class JexlTest extends JexlTestCase {
* test variables with underscore names
*/
@Test
- public void testVariableNames() throws Exception {
+ public void testVariableNames() {
final JexlContext jc = new MapContext();
jc.set("foo_bar", "123");
diff --git a/src/test/java/org/apache/commons/jexl3/internal/FqcnTest.java b/src/test/java/org/apache/commons/jexl3/internal/FqcnTest.java
new file mode 100644
index 00000000..52fe7e85
--- /dev/null
+++ b/src/test/java/org/apache/commons/jexl3/internal/FqcnTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.jexl3.internal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlTestCase;
+import org.apache.commons.jexl3.internal.introspection.Uberspect;
+import org.apache.commons.jexl3.introspection.JexlPermissions;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+public class FqcnTest extends JexlTestCase {
+ public static final int FORTYTWO = 42;
+ public FqcnTest() {
+ super("FqcnTest");
+ }
+
+ @BeforeEach
+ @Override
+ public void setUp() throws Exception {
+ // ensure jul logging is only error
+ java.util.logging.Logger.getLogger(org.apache.commons.jexl3.JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
+ }
+
+ @AfterEach
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public enum FqcnScope {
+ UNDEFINED, UNDECLARED, GLOBAL, LOCAL, THIS, SUPER;
+ }
+
+ Object getConstant(List<String> imports, String name) throws Exception {
+ JexlUberspect uber = new Uberspect(null, null, JexlPermissions.UNRESTRICTED);
+ final FqcnResolver resolver = new FqcnResolver(uber, imports);
+ return resolver.resolveConstant(name);
+ }
+
+ @Test
+ void testBadImport0() {
+ List<String> imports = Collections.singletonList("org.apache.commons.jexl4242");
+ assertThrows(JexlException.class, () -> new JexlBuilder().imports(imports).create());
+ }
+
+ @Test
+ void testBadImport1() {
+ // permissions will not allow this import
+ List<String> imports = Collections.singletonList("org.apache.commons.jexl.JexlEngine");
+ assertThrows(JexlException.class, () -> new JexlBuilder().imports(imports).create());
+ }
+
+ @Test
+ public void testFqcn() throws Exception {
+ List<String> imports = Arrays.asList("org.apache.commons.jexl3.internal.FqcnTest", "org.apache.commons.jexl3.internal", "java.lang");
+ Object c = getConstant(imports, "FqcnScope.UNDEFINED");
+ assertNotNull(c);
+ assertEquals(FqcnScope.UNDEFINED, c);
+ c = getConstant(imports, "FqcnScope.SUPER");
+ assertEquals(FqcnScope.SUPER, c);
+ c = getConstant(imports, "FqcnScope.SUPER");
+ assertEquals(FqcnScope.SUPER, c);
+ c = getConstant(imports, "FqcnTest.FORTYTWO");
+ assertEquals(42, c);
+ }
+}
diff --git a/src/test/java/org/apache/commons/jexl3/internal/RangeTest.java b/src/test/java/org/apache/commons/jexl3/internal/RangeTest.java
index 627e2a43..0f3b1fa0 100644
--- a/src/test/java/org/apache/commons/jexl3/internal/RangeTest.java
+++ b/src/test/java/org/apache/commons/jexl3/internal/RangeTest.java
@@ -40,10 +40,10 @@ import org.junit.jupiter.api.Test;
public class RangeTest extends JexlTestCase {
public RangeTest() {
- super("InternalTest");
+ super("RangeTest");
}
- private void checkIteration(final IntegerRange ir, final int first, final int last) throws Exception {
+ private void checkIteration(final IntegerRange ir, final int first, final int last) {
final Iterator<Integer> ii = ir.iterator();
if (ii.hasNext()) {
int l = ii.next();
@@ -57,7 +57,7 @@ public class RangeTest extends JexlTestCase {
}
}
- private void checkIteration(final LongRange lr, final long first, final long last) throws Exception {
+ private void checkIteration(final LongRange lr, final long first, final long last) {
final Iterator<Long> ii = lr.iterator();
if (ii.hasNext()) {
long l = ii.next();
@@ -85,7 +85,7 @@ public class RangeTest extends JexlTestCase {
}
@Test
- public void testAscIterator() {
+ void testAscIterator() {
final Iterator<Integer> ii = new AscIntegerIterator(3, 5);
Integer i = 3;
while (ii.hasNext()) {
@@ -97,7 +97,7 @@ public class RangeTest extends JexlTestCase {
}
@Test
- public void testAscLongIterator() {
+ void testAscLongIterator() {
final Iterator<Long> ii = new AscLongIterator(3L, 5L);
Long i = 3L;
while (ii.hasNext()) {
@@ -108,13 +108,13 @@ public class RangeTest extends JexlTestCase {
assertThrows(UnsupportedOperationException.class, ii::remove, "remove not implemented");
}
- @Test public void testMisc() {
+ @Test void testMisc() {
assertEquals("?", Scope.UNDEFINED.toString());
assertEquals("??", Scope.UNDECLARED.toString());
}
@Test
- public void testRanges() throws Exception {
+ void testRanges() throws Exception {
final LongRange lr0 = LongRange.create(20,10);
assertEquals(10L, lr0.getMin());
assertEquals(20L, lr0.getMax());
@@ -198,7 +198,7 @@ public class RangeTest extends JexlTestCase {
}
@Test
- public void testSource() {
+ void testSource() {
final JexlFeatures features = JexlFeatures.createDefault();
final Source src0 = new Source(features, "x -> -x");
final Source src0b = new Source(features, "x -> -x");