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 2016/07/03 17:27:00 UTC
svn commit: r1751163 - in /commons/proper/jexl/trunk/src:
main/java/org/apache/commons/jexl3/
main/java/org/apache/commons/jexl3/internal/
main/java/org/apache/commons/jexl3/parser/
test/java/org/apache/commons/jexl3/
Author: henrib
Date: Sun Jul 3 17:26:59 2016
New Revision: 1751163
URL: http://svn.apache.org/viewvc?rev=1751163&view=rev
Log:
JEXL:
Initial code for annotations JEXL-197 - @syntax
The @default part of the specification is not implemented (and probably wont) to avoid incurring a prohibitive evaluation cost);
The JexStatement/Interceptor parts have been simplified with Callable and JexlContext.AnnotationProcessor.
Added:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTAnnotation.java
- copied, changed from r1719037, commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AnnotationTest.java (with props)
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JXLTTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedContext.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedOverloadsTest.java
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java Sun Jul 3 17:26:59 2016
@@ -17,28 +17,30 @@
package org.apache.commons.jexl3;
+import java.util.concurrent.Callable;
+
/**
* Manages variables which can be referenced in a JEXL expression.
- *
+ *
* <p>JEXL variable names in their simplest form are 'java-like' identifiers.
* JEXL also considers 'ant' inspired variables expressions as valid.
* For instance, the expression 'x.y.z' is an 'antish' variable and will be resolved as a whole by the context,
* i.e. using the key "x.y.z". This proves to be useful to solve "fully qualified class names".</p>
- *
+ *
* <p>The interpreter variable resolution algorithm will try the different sequences of identifiers till it finds
* one that exists in the context; if "x" is an object known in the context (JexlContext.has("x") returns true),
* "x.y" will <em>not</em> be looked up in the context but will most likely refer to "x.getY()".</p>
- *
+ *
* <p>Note that JEXL may use '$jexl' and '$ujexl' variables for internal purpose; setting or getting those
* variables may lead to unexpected results unless specified otherwise.</p>
- *
+ *
* @since 1.0
*/
public interface JexlContext {
/**
* Gets the value of a variable.
- *
+ *
* @param name the variable's name
* @return the value
*/
@@ -46,7 +48,7 @@ public interface JexlContext {
/**
* Sets the value of a variable.
- *
+ *
* @param name the variable's name
* @param value the variable's value
*/
@@ -54,10 +56,10 @@ public interface JexlContext {
/**
* Checks whether a variable is defined in this context.
- *
+ *
* <p>A variable may be defined with a null value; this method checks whether the
* value is null or if the variable is undefined.</p>
- *
+ *
* @param name the variable's name
* @return true if it exists, false otherwise
*/
@@ -65,16 +67,16 @@ public interface JexlContext {
/**
* This interface declares how to resolve a namespace from its name; it is used by the interpreter during
- * evalutation.
- *
+ * evaluation.
+ *
* <p>In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance,
* the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc.</p>
- *
+ *
* In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns").
- *
+ *
* <p>JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to
* unexpected results.</p>
- *
+ *
* @since 3.0
*/
interface NamespaceResolver {
@@ -89,7 +91,7 @@ public interface JexlContext {
/**
* Namespace type that allows creating an instance to delegate namespace methods calls to.
- *
+ *
* <p>The functor is created once during the lifetime of a script evaluation.</p>
*/
interface NamespaceFunctor {
@@ -109,7 +111,7 @@ public interface JexlContext {
* keeping a reference to such a context is to be considered with great care and caution.
* It should also be noted that sharing such a context between threads should implicate synchronizing variable
* accessing the implementation class.
- *
+ *
* @see JexlEngine#setThreadContext(JexlContext.ThreadLocal)
* @see JexlEngine#getThreadContext()
*/
@@ -117,4 +119,21 @@ public interface JexlContext {
// no specific method
}
+ /**
+ * This interface declares how to process annotations; it is used by the interpreter during
+ * evaluation.
+ * <p>All annotations are processed through this method; the statement should be
+ */
+ interface AnnotationProcessor {
+ /**
+ * Processes an annotation.
+ * @param name the annotation name
+ * @param args the arguments
+ * @param statement the statement that was annotated; the processor should invoke this statement 'call' method
+ * @return the result of statement.call()
+ * @throws Exception if annotation processing fails
+ */
+ Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception;
+ }
+
}
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java Sun Jul 3 17:26:59 2016
@@ -31,7 +31,7 @@ import java.util.List;
/**
* Wraps any error that might occur during interpretation of a script or expression.
- *
+ *
* @since 2.0
*/
public class JexlException extends RuntimeException {
@@ -47,7 +47,7 @@ public class JexlException extends Runti
/**
* Creates a new JexlException.
- *
+ *
* @param node the node causing the error
* @param msg the error message
*/
@@ -57,7 +57,7 @@ public class JexlException extends Runti
/**
* Creates a new JexlException.
- *
+ *
* @param node the node causing the error
* @param msg the error message
* @param cause the exception causing the error
@@ -75,7 +75,7 @@ public class JexlException extends Runti
/**
* Creates a new JexlException.
- *
+ *
* @param jinfo the debugging information associated
* @param msg the error message
* @param cause the exception causing the error
@@ -88,7 +88,7 @@ public class JexlException extends Runti
/**
* Gets the specific information for this exception.
- *
+ *
* @return the information
*/
public JexlInfo getInfo() {
@@ -97,7 +97,7 @@ public class JexlException extends Runti
/**
* Creates a string builder pre-filled with common error information (if possible).
- *
+ *
* @param node the node
* @return a string builder
*/
@@ -115,7 +115,7 @@ public class JexlException extends Runti
/**
* Gets the most specific information attached to a node.
- *
+ *
* @param node the node
* @param info the information
* @return the information or null
@@ -137,7 +137,7 @@ public class JexlException extends Runti
/**
* Cleans a JexlException from any org.apache.commons.jexl3.internal stack trace element.
- *
+ *
* @return this exception
*/
public JexlException clean() {
@@ -146,7 +146,7 @@ public class JexlException extends Runti
/**
* Cleans a Throwable from any org.apache.commons.jexl3.internal stack trace element.
- *
+ *
* @param <X> the throwable type
* @param xthrow the thowable
* @return the throwable
@@ -168,7 +168,7 @@ public class JexlException extends Runti
/**
* Unwraps the cause of a throwable due to reflection.
- *
+ *
* @param xthrow the throwable
* @return the cause
*/
@@ -184,7 +184,7 @@ public class JexlException extends Runti
/**
* Merge the node info and the cause info to obtain best possible location.
- *
+ *
* @param info the node
* @param cause the cause
* @return the info to use
@@ -202,7 +202,7 @@ public class JexlException extends Runti
/**
* Accesses detailed message.
- *
+ *
* @return the message
*/
protected String detailedMessage() {
@@ -211,7 +211,7 @@ public class JexlException extends Runti
/**
* Formats an error message from the parser.
- *
+ *
* @param prefix the prefix to the message
* @param expr the expression in error
* @return the formatted message
@@ -235,7 +235,7 @@ public class JexlException extends Runti
/**
* Thrown when tokenization fails.
- *
+ *
* @since 3.0
*/
public static class Tokenization extends JexlException {
@@ -263,13 +263,13 @@ public class JexlException extends Runti
/**
* Thrown when parsing fails.
- *
+ *
* @since 3.0
*/
public static class Parsing extends JexlException {
/**
* Creates a new Parsing exception instance.
- *
+ *
* @param info the location information
* @param cause the javacc cause
*/
@@ -279,7 +279,7 @@ public class JexlException extends Runti
/**
* Creates a new Parsing exception instance.
- *
+ *
* @param info the location information
* @param msg the message
*/
@@ -302,7 +302,7 @@ public class JexlException extends Runti
/**
* Thrown when parsing fails due to an ambiguous statement.
- *
+ *
* @since 3.0
*/
public static class Ambiguous extends Parsing {
@@ -323,13 +323,13 @@ public class JexlException extends Runti
/**
* Thrown when parsing fails due to an invalid assigment.
- *
+ *
* @since 3.0
*/
public static class Assignment extends Parsing {
/**
* Creates a new Assignment statement exception instance.
- *
+ *
* @param info the location information
* @param expr the source expression line
*/
@@ -345,7 +345,7 @@ public class JexlException extends Runti
/**
* Thrown when a variable is unknown.
- *
+ *
* @since 3.0
*/
public static class Variable extends JexlException {
@@ -355,7 +355,7 @@ public class JexlException extends Runti
private final boolean undefined;
/**
* Creates a new Variable exception instance.
- *
+ *
* @param node the offending ASTnode
* @param var the unknown variable
* @param undef whether the variable is undefined or evaluated as null
@@ -367,7 +367,7 @@ public class JexlException extends Runti
/**
* Whether the variable causing an error is undefined or evaluated as null.
- *
+ *
* @return true if undefined, false otherwise
*/
public boolean isUndefined() {
@@ -389,7 +389,7 @@ public class JexlException extends Runti
/**
* Generates a message for a variable error.
- *
+ *
* @param node the node where the error occurred
* @param variable the variable
* @param undef whether the variable is null or undefined
@@ -409,13 +409,13 @@ public class JexlException extends Runti
/**
* Thrown when a property is unknown.
- *
+ *
* @since 3.0
*/
public static class Property extends JexlException {
/**
* Creates a new Property exception instance.
- *
+ *
* @param node the offending ASTnode
* @param var the unknown variable
*/
@@ -425,7 +425,7 @@ public class JexlException extends Runti
/**
* Creates a new Property exception instance.
- *
+ *
* @param node the offending ASTnode
* @param var the unknown variable
* @param cause the exception causing the error
@@ -449,7 +449,7 @@ public class JexlException extends Runti
/**
* Generates a message for an unsolvable property error.
- *
+ *
* @param node the node where the error occurred
* @param var the variable
* @return the error message
@@ -464,13 +464,13 @@ public class JexlException extends Runti
/**
* Thrown when a method or ctor is unknown, ambiguous or inaccessible.
- *
+ *
* @since 3.0
*/
public static class Method extends JexlException {
/**
* Creates a new Method exception instance.
- *
+ *
* @param node the offending ASTnode
* @param name the method name
*/
@@ -480,7 +480,7 @@ public class JexlException extends Runti
/**
* Creates a new Method exception instance.
- *
+ *
* @param info the location information
* @param name the unknown method
* @param cause the exception causing the error
@@ -504,7 +504,7 @@ public class JexlException extends Runti
/**
* Generates a message for a unsolvable method error.
- *
+ *
* @param node the node where the error occurred
* @param method the method name
* @return the error message
@@ -519,13 +519,13 @@ public class JexlException extends Runti
/**
* Thrown when an operator fails.
- *
+ *
* @since 3.0
*/
public static class Operator extends JexlException {
/**
* Creates a new Operator exception instance.
- *
+ *
* @param node the location information
* @param symbol the operator name
* @param cause the exception causing the error
@@ -549,7 +549,7 @@ public class JexlException extends Runti
/**
* Generates a message for an operator error.
- *
+ *
* @param node the node where the error occurred
* @param symbol the operator name
* @return the error message
@@ -563,8 +563,53 @@ public class JexlException extends Runti
}
/**
+ * Thrown when an annotation handler throws an exception.
+ *
+ * @since 3.1
+ */
+ public static class Annotation extends JexlException {
+ /**
+ * Creates a new Annotation exception instance.
+ *
+ * @param node the annotated statement node
+ * @param name the annotation name
+ * @param cause the exception causing the error
+ */
+ public Annotation(JexlNode node, String name, Throwable cause) {
+ super(node, name, cause);
+ }
+
+ /**
+ * @return the annotation name
+ */
+ public String getAnnotation() {
+ return super.detailedMessage();
+ }
+
+ @Override
+ protected String detailedMessage() {
+ return "error processing annotation '" + getAnnotation() + "'";
+ }
+ }
+
+ /**
+ * Generates a message for an annotation error.
+ *
+ * @param node the node where the error occurred
+ * @param annotation the annotation name
+ * @return the error message
+ */
+ public static String annotationError(JexlNode node, String annotation) {
+ StringBuilder msg = errorAt(node);
+ msg.append("error processing annotation '");
+ msg.append(annotation);
+ msg.append('\'');
+ return msg.toString();
+ }
+
+ /**
* Thrown to return a value.
- *
+ *
* @since 3.0
*/
public static class Return extends JexlException {
@@ -574,7 +619,7 @@ public class JexlException extends Runti
/**
* Creates a new instance of Return.
- *
+ *
* @param node the return node
* @param msg the message
* @param value the returned value
@@ -594,13 +639,13 @@ public class JexlException extends Runti
/**
* Thrown to cancel a script execution.
- *
+ *
* @since 3.0
*/
public static class Cancel extends JexlException {
/**
* Creates a new instance of Cancel.
- *
+ *
* @param node the node where the interruption was detected
*/
public Cancel(JexlNode node) {
@@ -610,13 +655,13 @@ public class JexlException extends Runti
/**
* Thrown to break a loop.
- *
+ *
* @since 3.0
*/
public static class Break extends JexlException {
/**
* Creates a new instance of Break.
- *
+ *
* @param node the break
*/
public Break(JexlNode node) {
@@ -626,13 +671,13 @@ public class JexlException extends Runti
/**
* Thrown to continue a loop.
- *
+ *
* @since 3.0
*/
public static class Continue extends JexlException {
/**
* Creates a new instance of Continue.
- *
+ *
* @param node the continue
*/
public Continue(JexlNode node) {
@@ -648,7 +693,7 @@ public class JexlException extends Runti
* - begin, end are character offsets in the string for the precise location of the error
* - string is the string representation of the offending expression
* - msg is the actual explanation message for this error
- *
+ *
* @return this error as a string
*/
@Override
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java Sun Jul 3 17:26:59 2016
@@ -94,6 +94,8 @@ import org.apache.commons.jexl3.parser.J
import org.apache.commons.jexl3.parser.ParserVisitor;
import java.util.regex.Pattern;
+import org.apache.commons.jexl3.parser.ASTAnnotatedStatement;
+import org.apache.commons.jexl3.parser.ASTAnnotation;
/**
* Helps pinpoint the cause of problems in expressions that fail during evaluation.
@@ -959,4 +961,32 @@ public class Debugger extends ParserVisi
String img = node.getLiteral().replace("`", "\\`");
return check(node, "`" + img + "`", data);
}
+
+ @Override
+ protected Object visit(ASTAnnotation node, Object data) {
+ int num = node.jjtGetNumChildren();
+ builder.append('@');
+ builder.append(node.getName());
+ if (num > 0) {
+ builder.append("(");
+ accept(node.jjtGetChild(0), data);
+ for(int i = 0; i < num; ++i) {
+ builder.append(", ");
+ JexlNode child = node.jjtGetChild(i);
+ acceptStatement(child, data);
+ }
+ builder.append(")");
+ }
+ return null;
+ }
+
+ @Override
+ protected Object visit(ASTAnnotatedStatement node, Object data) {
+ int num = node.jjtGetNumChildren();
+ for (int i = 0; i < num; ++i) {
+ JexlNode child = node.jjtGetChild(i);
+ acceptStatement(child, data);
+ }
+ return data;
+ }
}
\ No newline at end of file
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java Sun Jul 3 17:26:59 2016
@@ -16,21 +16,22 @@
*/
package org.apache.commons.jexl3.internal;
+
import org.apache.commons.jexl3.JexlArithmetic;
-import org.apache.commons.jexl3.JexlOperator;
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlOperator;
import org.apache.commons.jexl3.JexlScript;
-
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
import org.apache.commons.jexl3.introspection.JexlPropertySet;
import org.apache.commons.jexl3.introspection.JexlUberspect;
import org.apache.commons.jexl3.introspection.JexlUberspect.PropertyResolver;
-
import org.apache.commons.jexl3.parser.ASTAddNode;
import org.apache.commons.jexl3.parser.ASTAndNode;
+import org.apache.commons.jexl3.parser.ASTAnnotatedStatement;
+import org.apache.commons.jexl3.parser.ASTAnnotation;
import org.apache.commons.jexl3.parser.ASTArguments;
import org.apache.commons.jexl3.parser.ASTArrayAccess;
import org.apache.commons.jexl3.parser.ASTArrayLiteral;
@@ -102,10 +103,13 @@ import org.apache.commons.jexl3.parser.A
import org.apache.commons.jexl3.parser.JexlNode;
import org.apache.commons.jexl3.parser.Node;
import org.apache.commons.jexl3.parser.ParserVisitor;
+
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
+
import org.apache.commons.logging.Log;
/**
@@ -135,7 +139,7 @@ public class Interpreter extends ParserV
/** The context to store/retrieve variables. */
protected final JexlContext.NamespaceResolver ns;
/** Strict interpreter flag (may temporarily change when calling size and empty as functions). */
- protected boolean strictEngine;
+ protected final boolean strictEngine;
/** Strict interpreter flag. */
protected final boolean strictArithmetic;
/** Silent interpreter flag. */
@@ -167,7 +171,7 @@ public class Interpreter extends ParserV
Boolean ocancellable = opts.isCancellable();
this.strictEngine = ostrict == null ? jexl.isStrict() : ostrict;
this.silent = osilent == null ? jexl.isSilent() : osilent;
- this.cancellable = ocancellable == null? jexl.cancellable : ocancellable;
+ this.cancellable = ocancellable == null ? jexl.cancellable : ocancellable;
this.arithmetic = jexl.arithmetic.options(opts);
} else {
this.strictEngine = jexl.isStrict();
@@ -250,14 +254,14 @@ public class Interpreter extends ParserV
protected void closeIfSupported(Object closeable) {
if (closeable != null) {
//if (AUTOCLOSEABLE == null || AUTOCLOSEABLE.isAssignableFrom(closeable.getClass())) {
- JexlMethod mclose = uberspect.getMethod(closeable, "close", EMPTY_PARAMS);
- if (mclose != null) {
- try {
- mclose.invoke(closeable, EMPTY_PARAMS);
- } catch (Exception xignore) {
- logger.warn(xignore);
- }
+ JexlMethod mclose = uberspect.getMethod(closeable, "close", EMPTY_PARAMS);
+ if (mclose != null) {
+ try {
+ mclose.invoke(closeable, EMPTY_PARAMS);
+ } catch (Exception xignore) {
+ logger.warn(xignore);
}
+ }
//}
}
}
@@ -360,8 +364,8 @@ public class Interpreter extends ParserV
logger.warn(xjexl.getMessage(), xjexl.getCause());
}
if (strictEngine
- || xjexl instanceof JexlException.Return
- || xjexl instanceof JexlException.Cancel) {
+ || xjexl instanceof JexlException.Return
+ || xjexl instanceof JexlException.Cancel) {
throw xjexl;
}
return null;
@@ -369,9 +373,9 @@ public class Interpreter extends ParserV
/**
* Wraps an exception thrown by an invocation.
- * @param node the node triggering the exception
+ * @param node the node triggering the exception
* @param methodName the method/function name
- * @param xany the cause
+ * @param xany the cause
* @return a JexlException
*/
protected JexlException invocationException(JexlNode node, String methodName, Exception xany) {
@@ -387,6 +391,22 @@ public class Interpreter extends ParserV
}
/**
+ * Triggered when an annotation processing fails.
+ * @param node the node where the error originated from
+ * @param annotation the annotation name
+ * @param cause the cause of error (if any)
+ * @throws JexlException if isStrict
+ */
+ protected void annotationError(JexlNode node, String annotation, Throwable cause) {
+ if (!silent) {
+ logger.warn(JexlException.annotationError(node, annotation), cause);
+ }
+ if (strictEngine) {
+ throw new JexlException.Annotation(node, annotation, cause);
+ }
+ }
+
+ /**
* Cancels this evaluation, setting the cancel flag that will result in a JexlException.Cancel to be thrown.
* @return false if already cancelled, true otherwise
*/
@@ -404,10 +424,10 @@ public class Interpreter extends ParserV
* @return true if canceled, false otherwise
*/
protected boolean isCancelled() {
- if (!cancelled) {
- cancelled = Thread.currentThread().isInterrupted();
- }
- return cancelled;
+ if (!cancelled) {
+ cancelled = Thread.currentThread().isInterrupted();
+ }
+ return cancelled;
}
/** @return true if interrupt throws a JexlException.Cancel. */
@@ -766,7 +786,7 @@ public class Interpreter extends ParserV
n = 1;
result = node.jjtGetChild(n).jjtAccept(this, null);
} else {
- // if there is a false, execute it. false statement is the second
+ // if there is a false, execute it. false statement is the second
// objectNode
if (node.jjtGetNumChildren() == 3) {
n = 2;
@@ -829,8 +849,8 @@ public class Interpreter extends ParserV
try {
forEach = operators.tryForeachOverload(node, iterableValue);
Iterator<?> itemsIterator = forEach instanceof Iterator
- ? (Iterator<?>) forEach
- : uberspect.getIterator(iterableValue);
+ ? (Iterator<?>) forEach
+ : uberspect.getIterator(iterableValue);
if (itemsIterator != null) {
while (itemsIterator.hasNext()) {
if (isCancelled()) {
@@ -897,7 +917,7 @@ public class Interpreter extends ParserV
if (!leftValue) {
return Boolean.FALSE;
}
- } catch (RuntimeException xrt) {
+ } catch (ArithmeticException xrt) {
throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt);
}
Object right = node.jjtGetChild(1).jjtAccept(this, data);
@@ -1057,13 +1077,11 @@ public class Interpreter extends ParserV
@Override
protected Object visit(ASTSizeFunction node, Object data) {
- boolean isStrict = this.strictEngine;
try {
- strictEngine = false;
Object val = node.jjtGetChild(0).jjtAccept(this, data);
return operators.size(node, val);
- } finally {
- strictEngine = isStrict;
+ } catch(JexlException xany) {
+ return 0;
}
}
@@ -1075,13 +1093,11 @@ public class Interpreter extends ParserV
@Override
protected Object visit(ASTEmptyFunction node, Object data) {
- boolean isStrict = this.strictEngine;
try {
- strictEngine = false;
Object value = node.jjtGetChild(0).jjtAccept(this, data);
return operators.empty(node, value);
- } finally {
- strictEngine = isStrict;
+ } catch(JexlException xany) {
+ return true;
}
}
@@ -1531,9 +1547,9 @@ public class Interpreter extends ParserV
/**
* Concatenate arguments in call(...).
* <p>When target == context, we are dealing with a global namespace function call
- * @param target the pseudo-method owner, first to-be argument
- * @param narrow whether we should attempt to narrow number arguments
- * @param args the other (non null) arguments
+ * @param target the pseudo-method owner, first to-be argument
+ * @param narrow whether we should attempt to narrow number arguments
+ * @param args the other (non null) arguments
* @return the arguments array
*/
private Object[] functionArguments(Object target, boolean narrow, Object[] args) {
@@ -1548,7 +1564,7 @@ public class Interpreter extends ParserV
Object[] nargv = new Object[args.length + 1];
if (narrow) {
nargv[0] = functionArgument(true, target);
- for(int a = 1; a <= args.length; ++a) {
+ for (int a = 1; a <= args.length; ++a) {
nargv[a] = functionArgument(true, args[a - 1]);
}
} else {
@@ -1561,11 +1577,11 @@ public class Interpreter extends ParserV
/**
* Optionally narrows an argument for a function call.
* @param narrow whether narrowing should occur
- * @param arg the argument
+ * @param arg the argument
* @return the narrowed argument
*/
private Object functionArgument(boolean narrow, Object arg) {
- return narrow && arg instanceof Number ? arithmetic.narrow((Number) arg) : arg;
+ return narrow && arg instanceof Number ? arithmetic.narrow((Number) arg) : arg;
}
/**
@@ -1578,7 +1594,7 @@ public class Interpreter extends ParserV
protected final JexlMethod me;
/**
* Constructor.
- * @param jme the method
+ * @param jme the method
* @param flag the narrow flag
*/
protected Funcall(JexlMethod jme, boolean flag) {
@@ -1588,10 +1604,10 @@ public class Interpreter extends ParserV
/**
* Try invocation.
- * @param ii the interpreter
- * @param name the method name
+ * @param ii the interpreter
+ * @param name the method name
* @param target the method target
- * @param args the method arguments
+ * @param args the method arguments
* @return the method invocation result (or JexlEngine.TRY_FAILED)
*/
protected Object tryInvoke(Interpreter ii, String name, Object target, Object[] args) {
@@ -1605,7 +1621,7 @@ public class Interpreter extends ParserV
private static class ArithmeticFuncall extends Funcall {
/**
* Constructor.
- * @param jme the method
+ * @param jme the method
* @param flag the narrow flag
*/
protected ArithmeticFuncall(JexlMethod jme, boolean flag) {
@@ -1617,13 +1633,14 @@ public class Interpreter extends ParserV
return me.tryInvoke(name, ii.arithmetic, ii.functionArguments(target, narrow, args));
}
}
+
/**
* Cached context function call.
*/
private static class ContextFuncall extends Funcall {
/**
* Constructor.
- * @param jme the method
+ * @param jme the method
* @param flag the narrow flag
*/
protected ContextFuncall(JexlMethod jme, boolean flag) {
@@ -1733,13 +1750,12 @@ public class Interpreter extends ParserV
if (namespace == context) {
// we can not solve it
break;
- }
- else if (namespace != null) {
+ } else if (namespace != null) {
target = namespace;
caller = null;
continue;
}
- // could not find a method, try as a property of a non-context target (performed once)
+ // could not find a method, try as a property of a non-context target (performed once)
} else if (!narrow) {
// the method may be a functor stored in a property of the target
JexlPropertyGet get = uberspect.getPropertyGet(target, methodName);
@@ -1762,7 +1778,7 @@ public class Interpreter extends ParserV
if (vm != null) {
return vm.invoke(functor, argv);
}
- // try JexlArithmetic or JexlContext function
+ // try JexlArithmetic or JexlContext function
} else {
// no need to narrow since this has been performed in previous loop
Object[] nargv = functionArguments(caller, narrow, argv);
@@ -1893,7 +1909,7 @@ public class Interpreter extends ParserV
throw new JexlException.Cancel(node);
}
final JexlOperator operator = node != null && node.jjtGetParent() instanceof ASTArrayAccess
- ? JexlOperator.ARRAY_GET : JexlOperator.PROPERTY_GET;
+ ? JexlOperator.ARRAY_GET : JexlOperator.PROPERTY_GET;
Object result = operators.tryOverload(node, operator, object, attribute);
if (result != JexlEngine.TRY_FAILED) {
return result;
@@ -1912,7 +1928,7 @@ public class Interpreter extends ParserV
// resolve that property
Exception xcause = null;
List<PropertyResolver> resolvers = uberspect.getResolvers(operator, object);
- JexlPropertyGet vg = uberspect.getPropertyGet(resolvers, object, attribute);
+ JexlPropertyGet vg = uberspect.getPropertyGet(resolvers, object, attribute);
if (vg != null) {
try {
Object value = vg.invoke(object);
@@ -1962,7 +1978,7 @@ public class Interpreter extends ParserV
throw new JexlException.Cancel(node);
}
final JexlOperator operator = node != null && node.jjtGetParent() instanceof ASTArrayAccess
- ? JexlOperator.ARRAY_SET : JexlOperator.PROPERTY_SET;
+ ? JexlOperator.ARRAY_SET : JexlOperator.PROPERTY_SET;
Object result = operators.tryOverload(node, operator, object, attribute, value);
if (result != JexlEngine.TRY_FAILED) {
return;
@@ -2019,14 +2035,82 @@ public class Interpreter extends ParserV
protected Object visit(ASTJxltLiteral node, Object data) {
TemplateEngine.TemplateExpression tp = (TemplateEngine.TemplateExpression) node.jjtGetValue();
if (tp == null) {
- TemplateEngine jxlt = jexl.jxlt();
- tp = jxlt.parseExpression(node.jexlInfo(), node.getLiteral(), frame != null? frame.getScope() : null);
- node.jjtSetValue(tp);
+ TemplateEngine jxlt = jexl.jxlt();
+ tp = jxlt.parseExpression(node.jexlInfo(), node.getLiteral(), frame != null ? frame.getScope() : null);
+ node.jjtSetValue(tp);
}
if (tp != null) {
- return tp.evaluate(frame, context);
+ return tp.evaluate(frame, context);
+ }
+ return null;
+ }
+
+ @Override
+ protected Object visit(ASTAnnotation node, Object data) {
+ throw new UnsupportedOperationException(ASTAnnotation.class.getName() + ": Not supported.");
+ }
+
+ @Override
+ protected Object visit(ASTAnnotatedStatement node, Object data) {
+ return processAnnotation(node, 0, data);
+ }
+
+ /**
+ * Processes an annotated statement.
+ * @param stmt the statement
+ * @param index the index of the current annotation being processed
+ * @param data the contextual data
+ * @return the result of the statement block evaluation
+ */
+ protected Object processAnnotation(final ASTAnnotatedStatement stmt, final int index, final Object data) {
+ // are we evaluating the block ?
+ final int last = stmt.jjtGetNumChildren() - 1;
+ if (index == last) {
+ JexlNode block = stmt.jjtGetChild(last);
+ return block.jjtAccept(Interpreter.this, data);
+ }
+ // tracking whether we processed the annotation
+ final boolean[] processed = new boolean[]{false};
+ final Callable<Object> jstmt = new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ processed[0] = true;
+ return processAnnotation(stmt, index + 1, data);
+ }
+ };
+ // the annotation node and name
+ final ASTAnnotation anode = (ASTAnnotation) stmt.jjtGetChild(index);
+ final String aname = anode.getName();
+ // evaluate the arguments
+ Object[] argv = anode.jjtGetNumChildren() > 0
+ ? visit((ASTArguments) anode.jjtGetChild(0), null) : null;
+ // wrap the future, will recurse through annotation processor
+ try {
+ Object result = processAnnotation(aname, argv, jstmt);
+ // not processing an annotation is an error
+ if (!processed[0]) {
+ annotationError(anode, aname, null);
+ }
+ return result;
+ } catch(JexlException xjexl) {
+ throw xjexl;
+ } catch(Exception xany) {
+ annotationError(anode, aname, xany);
}
return null;
}
+ /**
+ * Delegates the annotation processing to the JexlContext if it is an AnnotationProcessor.
+ * @param annotation the annotation name
+ * @param args the annotation arguments
+ * @param stmt the statement / block that was annotated
+ * @return the result of statement.call()
+ * @throws Exception if anything goes wrong
+ */
+ protected Object processAnnotation(String annotation, Object[] args, Callable<Object> stmt) throws Exception {
+ return context instanceof JexlContext.AnnotationProcessor
+ ? ((JexlContext.AnnotationProcessor) context).processAnnotation(annotation, args, stmt)
+ : stmt.call();
+ }
}
Copied: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTAnnotation.java (from r1719037, commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java)
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTAnnotation.java?p2=commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTAnnotation.java&p1=commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java&r1=1719037&r2=1751163&rev=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTAnnotation.java Sun Jul 3 17:26:59 2016
@@ -17,17 +17,16 @@
package org.apache.commons.jexl3.parser;
/**
- * Identifiers, variables, ie symbols.
+ * Annotation.
*/
-public class ASTIdentifier extends JexlNode {
+public class ASTAnnotation extends JexlNode {
private String name = null;
- private int symbol = -1;
- ASTIdentifier(int id) {
+ ASTAnnotation(int id) {
super(id);
}
- ASTIdentifier(Parser p, int id) {
+ ASTAnnotation(Parser p, int id) {
super(p, id);
}
@@ -36,20 +35,12 @@ public class ASTIdentifier extends JexlN
return name;
}
- void setSymbol(String identifier) {
- if (identifier.charAt(0) == '#') {
- symbol = Integer.parseInt(identifier.substring(1));
+ void setName(String identifier) {
+ if (identifier.charAt(0) == '@') {
+ name = identifier.substring(1);
+ } else {
+ name = identifier;
}
- name = identifier;
- }
-
- void setSymbol(int r, String identifier) {
- symbol = r;
- name = identifier;
- }
-
- public int getSymbol() {
- return symbol;
}
public String getName() {
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt Sun Jul 3 17:26:59 2016
@@ -203,6 +203,11 @@ TOKEN_MGR_DECLS : {
< NAN_LITERAL : "NaN" >
}
+<*> TOKEN : /* ANNOTATION */
+{
+ < ANNOTATION: "@" ( [ "0"-"9", "a"-"z", "A"-"Z", "_", "$" ])+ >
+}
+
<DOT_ID> TOKEN : /* IDENTIFIERS */
{
< DOT_IDENTIFIER: ( [ "0"-"9", "a"-"z", "A"-"Z", "_", "$", "@" ])+ > { popDot(); } /* Revert state to default. */
@@ -278,11 +283,25 @@ ASTJexlScript JexlExpression(Scope frame
}
}
+void Annotation() #Annotation :
+{
+ Token t;
+}
+{
+ t=<ANNOTATION> (LOOKAHEAD(<LPAREN>) Arguments() )? { jjtThis.setName(t.image); }
+}
+
+void AnnotatedStatement() #AnnotatedStatement() : {}
+{
+ (LOOKAHEAD(<ANNOTATION>) Annotation())+ (LOOKAHEAD(1) Block() | Expression())
+}
+
void Statement() #void : {}
{
<SEMICOL>
- | LOOKAHEAD(<LCURLY> Expression() <SEMICOL>) Block() // to diasmbiguate the set literals
- | LOOKAHEAD(<LCURLY> Statement() <SEMICOL>) Block() // to diasmbiguate the set literals
+ | LOOKAHEAD(<ANNOTATION>) AnnotatedStatement()
+ | LOOKAHEAD(<LCURLY> Expression() <SEMICOL>) Block() // to disambiguate the set literals
+ | LOOKAHEAD(<LCURLY> Statement() <SEMICOL>) Block() // to disambiguate the set literals
| IfStatement()
| ForeachStatement()
| WhileStatement()
@@ -841,7 +860,3 @@ void ValueExpression() #void : {}
( PrimaryExpression() ( LOOKAHEAD(2) MemberExpression() )*) #Reference(>1)
}
-
-
-
-
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java Sun Jul 3 17:26:59 2016
@@ -27,7 +27,7 @@ public abstract class ParserVisitor {
* @return does not return
*/
protected final Object visit(SimpleNode node, Object data) {
- throw new UnsupportedOperationException("Not supported yet.");
+ throw new UnsupportedOperationException(node.getClass().getSimpleName() + " : not supported yet.");
}
/**
@@ -177,4 +177,8 @@ public abstract class ParserVisitor {
protected abstract Object visit(ASTSetXorNode node, Object data);
protected abstract Object visit(ASTJxltLiteral node, Object data);
+
+ protected abstract Object visit(ASTAnnotation node, Object data);
+
+ protected abstract Object visit(ASTAnnotatedStatement node, Object data);
}
Added: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AnnotationTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AnnotationTest.java?rev=1751163&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AnnotationTest.java (added)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AnnotationTest.java Sun Jul 3 17:26:59 2016
@@ -0,0 +1,156 @@
+/*
+ * 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
+ *
+ * http://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;
+
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for annotations.
+ * @since 3.1
+ */
+@SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
+
+public class AnnotationTest extends JexlTestCase {
+
+ public AnnotationTest() {
+ super("AnnotationTest");
+ }
+
+ @Test
+ public void test197a() throws Exception {
+ JexlContext jc = new MapContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@synchronized { return 42; }");
+ Object r = e.execute(jc);
+ Assert.assertEquals(42, r);
+ }
+
+ public static class AnnotationContext extends MapContext implements JexlContext.AnnotationProcessor {
+ private int count = 0;
+ private final Set<String> names = new TreeSet<String>();
+
+ @Override
+ public Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception {
+ count += 1;
+ names.add(name);
+ if ("one".equals(name)) {
+ names.add(args[0].toString());
+ } else if ("two".equals(name)) {
+ names.add(args[0].toString());
+ names.add(args[1].toString());
+ } else if ("error".equals(name)) {
+ names.add(args[0].toString());
+ throw new IllegalArgumentException(args[0].toString());
+ } else if ("unknown".equals(name)) {
+ return null;
+ }
+ return statement.call();
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public Set<String> getNames() {
+ return names;
+ }
+ }
+
+ @Test
+ public void testNoArg() throws Exception {
+ AnnotationContext jc = new AnnotationContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@synchronized { return 42; }");
+ Object r = e.execute(jc);
+ Assert.assertEquals(42, r);
+ Assert.assertEquals(1, jc.getCount());
+ Assert.assertTrue(jc.getNames().contains("synchronized"));
+ }
+
+ @Test
+ public void testNoArgExpression() throws Exception {
+ AnnotationContext jc = new AnnotationContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@synchronized 42");
+ Object r = e.execute(jc);
+ Assert.assertEquals(42, r);
+ Assert.assertEquals(1, jc.getCount());
+ Assert.assertTrue(jc.getNames().contains("synchronized"));
+ }
+
+
+ @Test
+ public void testOneArg() throws Exception {
+ AnnotationContext jc = new AnnotationContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@one(1) { return 42; }");
+ Object r = e.execute(jc);
+ Assert.assertEquals(42, r);
+ Assert.assertEquals(1, jc.getCount());
+ Assert.assertTrue(jc.getNames().contains("one"));
+ Assert.assertTrue(jc.getNames().contains("1"));
+ }
+
+ @Test
+ public void testMultiple() throws Exception {
+ AnnotationContext jc = new AnnotationContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@one(1) @synchronized { return 42; }");
+ Object r = e.execute(jc);
+ Assert.assertEquals(42, r);
+ Assert.assertEquals(2, jc.getCount());
+ Assert.assertTrue(jc.getNames().contains("synchronized"));
+ Assert.assertTrue(jc.getNames().contains("one"));
+ Assert.assertTrue(jc.getNames().contains("1"));
+ }
+
+ @Test
+ public void testError() throws Exception {
+ AnnotationContext jc = new AnnotationContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@error('42') { return 42; }");
+ try {
+ Object r = e.execute(jc);
+ Assert.fail("should have failed");
+ } catch (JexlException.Annotation xjexl) {
+ Assert.assertEquals("error", xjexl.getAnnotation());
+ }
+ Assert.assertEquals(1, jc.getCount());
+ Assert.assertTrue(jc.getNames().contains("error"));
+ Assert.assertTrue(jc.getNames().contains("42"));
+ }
+
+ @Test
+ public void testUnknown() throws Exception {
+ AnnotationContext jc = new AnnotationContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("@unknown('42') { return 42; }");
+ try {
+ Object r = e.execute(jc);
+ Assert.fail("should have failed");
+ } catch (JexlException.Annotation xjexl) {
+ Assert.assertEquals("unknown", xjexl.getAnnotation());
+ }
+ Assert.assertEquals(1, jc.getCount());
+ Assert.assertTrue(jc.getNames().contains("unknown"));
+ Assert.assertFalse(jc.getNames().contains("42"));
+ }
+}
Propchange: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AnnotationTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java Sun Jul 3 17:26:59 2016
@@ -95,6 +95,16 @@ public class ArithmeticOperatorTest exte
}
@Test
+ public void testStartsEndsWithStringDot() throws Exception {
+ asserter.setVariable("x.y", "foobar");
+ asserter.assertExpression("x.y =^ 'foo'", Boolean.TRUE);
+ asserter.assertExpression("x.y =$ 'foo'", Boolean.FALSE);
+ asserter.setVariable("x.y", "barfoo");
+ asserter.assertExpression("x.y =^ 'foo'", Boolean.FALSE);
+ asserter.assertExpression("x.y =$ 'foo'", Boolean.TRUE);
+ }
+
+ @Test
public void testNotStartsEndsWithString() throws Exception {
asserter.setVariable("x", "foobar");
asserter.assertExpression("x !^ 'foo'", Boolean.FALSE);
@@ -104,6 +114,16 @@ public class ArithmeticOperatorTest exte
asserter.assertExpression("x !$ 'foo'", Boolean.FALSE);
}
+ @Test
+ public void testNotStartsEndsWithStringDot() throws Exception {
+ asserter.setVariable("x.y", "foobar");
+ asserter.assertExpression("x.y !^ 'foo'", Boolean.FALSE);
+ asserter.assertExpression("x.y !$ 'foo'", Boolean.TRUE);
+ asserter.setVariable("x.y", "barfoo");
+ asserter.assertExpression("x.y !^ 'foo'", Boolean.TRUE);
+ asserter.assertExpression("x.y !$ 'foo'", Boolean.FALSE);
+ }
+
public static class MatchingContainer {
private final Set<Integer> values;
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java Sun Jul 3 17:26:59 2016
@@ -1163,4 +1163,51 @@ public class IssuesTest extends JexlTest
jc.set("t", null);
Assert.assertNull(js0.evaluate(jc));
}
+
+ @Test
+ public void test199() throws Exception {
+ JexlContext jc = new MapContext();
+ JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(false)).create();
+
+ JexlScript e = jexl.createScript("(x, y)->{ x + y }");
+ Object r = e.execute(jc, true, "EURT");
+ Assert.assertEquals("trueEURT", r);
+ r = e.execute(jc, "ELSAF", false);
+ Assert.assertEquals("ELSAFfalse", r);
+ }
+
+ public static class Eval {
+ private JexlEngine jexl;
+
+ public JexlScript fn(String src) {
+ return jexl.createScript(src);
+ }
+
+ void setJexl(JexlEngine je) {
+ jexl = je;
+ }
+ }
+
+ @Test
+ public void test200() throws Exception {
+ JexlContext jc = new MapContext();
+ Map<String, Object> funcs = new HashMap<String, Object>();
+ Eval eval = new Eval();
+ funcs.put(null, eval);
+ JexlEngine jexl = new JexlBuilder().namespaces(funcs).create();
+ eval.setJexl(jexl);
+ String src = "var f = fn(\'(x)->{x + 42}\'); f(y)";
+ JexlScript s200 = jexl.createScript(src, "y");
+ Assert.assertEquals(142, s200.execute(jc, 100));
+ Assert.assertEquals(52, s200.execute(jc, 10));
+ }
+
+ @Test
+ public void test200b() throws Exception {
+ JexlContext jc = new MapContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript e = jexl.createScript("var x = 0; var f = (y)->{ x = y; }; f(42); x");
+ Object r = e.execute(jc);
+ Assert.assertEquals(0, r);
+ }
}
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JXLTTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JXLTTest.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JXLTTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JXLTTest.java Sun Jul 3 17:26:59 2016
@@ -680,10 +680,14 @@ public class JXLTTest extends JexlTestCa
@Test
public void testInterpolation() throws Exception {
- context.set("user", "Dimitri");
String expr = "`Hello \n${user}`";
- Object value = JEXL.createScript(expr).execute(context);
+ JexlScript script = JEXL.createScript(expr);
+ context.set("user", "Dimitri");
+ Object value = script.execute(context);
Assert.assertEquals(expr, "Hello \nDimitri", value);
+ context.set("user", "Rahul");
+ value = script.execute(context);
+ Assert.assertEquals(expr, "Hello \nRahul", value);
}
@Test
@@ -718,6 +722,8 @@ public class JXLTTest extends JexlTestCa
String expr = "(user)->{`Hello \n${user}`}";
Object value = JEXL.createScript(expr).execute(context, "Henrib");
Assert.assertEquals(expr, "Hello \nHenrib", value);
+ value = JEXL.createScript(expr).execute(context, "Dimitri");
+ Assert.assertEquals(expr, "Hello \nDimitri", value);
}
//
//
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java Sun Jul 3 17:26:59 2016
@@ -62,7 +62,35 @@ public class ScriptCallableTest extends
}
@Test
- public void testCallable() throws Exception {
+ public void testCallableCancel() throws Exception {
+ JexlScript e = JEXL.createScript("while(true);");
+ final Script.Callable c = (Script.Callable) e.callable(null);
+ Object t = 42;
+ Callable<Object> kc = new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ return c.cancel();
+ }
+
+ };
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ Future<?> future = executor.submit(c);
+ Future<?> kfc = executor.submit(kc);
+ try {
+ Assert.assertTrue((Boolean) kfc.get());
+ t = future.get();
+ Assert.fail("should have been cancelled");
+ } catch (ExecutionException xexec) {
+ // ok, ignore
+ Assert.assertTrue(xexec.getCause() instanceof JexlException.Cancel);
+ } finally {
+ executor.shutdown();
+ }
+ Assert.assertTrue(c.isCancelled());
+ }
+
+ @Test
+ public void testCallableTimeout() throws Exception {
JexlScript e = JEXL.createScript("while(true);");
Callable<Object> c = e.callable(null);
Object t = 42;
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java Sun Jul 3 17:26:59 2016
@@ -84,6 +84,45 @@ public class SideEffectTest extends Jexl
}
@Test
+ public void testSideEffectVarDots() throws Exception {
+ Map<String,Object> context = asserter.getVariables();
+ Integer i41 = Integer.valueOf(4141);
+ Object foo = i41;
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux += 2", i41 + 2);
+ Assert.assertEquals(context.get("foo.bar.quux"), i41 + 2);
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux -= 2", i41 - 2);
+ Assert.assertEquals(context.get("foo.bar.quux"), i41 - 2);
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux *= 2", i41 * 2);
+ Assert.assertEquals(context.get("foo.bar.quux"), i41 * 2);
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux /= 2", i41 / 2);
+ Assert.assertEquals(context.get("foo.bar.quux"), i41 / 2);
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux %= 2", i41 % 2);
+ Assert.assertEquals(context.get("foo.bar.quux"), i41 % 2);
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux &= 3", (long) (i41 & 3));
+ Assert.assertEquals(context.get("foo.bar.quux"), (long)(i41 & 3));
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux |= 2", (long)(i41 | 2));
+ Assert.assertEquals(context.get("foo.bar.quux"), (long)(i41 | 2));
+
+ context.put("foo.bar.quux", foo);
+ asserter.assertExpression("foo.bar.quux ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(context.get("foo.bar.quux"), (long)(i41 ^ 2));
+ }
+
+ @Test
public void testSideEffectArray() throws Exception {
Integer i41 = Integer.valueOf(4141);
Integer i42 = Integer.valueOf(42);
@@ -120,6 +159,43 @@ public class SideEffectTest extends Jexl
Assert.assertEquals(foo[0], (long)(i41 ^ 2));
}
+ @Test
+ public void testSideEffectDotArray() throws Exception {
+ Integer i41 = Integer.valueOf(4141);
+ Integer i42 = Integer.valueOf(42);
+ Integer i43 = Integer.valueOf(43);
+ String s42 = "fourty-two";
+ String s43 = "fourty-three";
+ Object[] foo = new Object[3];
+ foo[1] = i42;
+ foo[2] = i43;
+ asserter.setVariable("foo", foo);
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 += 2", i41 + 2);
+ Assert.assertEquals(foo[0], i41 + 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 -= 2", i41 - 2);
+ Assert.assertEquals(foo[0], i41 - 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 *= 2", i41 * 2);
+ Assert.assertEquals(foo[0], i41 * 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 /= 2", i41 / 2);
+ Assert.assertEquals(foo[0], i41 / 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 %= 2", i41 % 2);
+ Assert.assertEquals(foo[0], i41 % 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 &= 3", (long) (i41 & 3));
+ Assert.assertEquals(foo[0], (long)(i41 & 3));
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 |= 2", (long)(i41 | 2));
+ Assert.assertEquals(foo[0], (long)(i41 | 2));
+ foo[0] = i41;
+ asserter.assertExpression("foo.0 ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(foo[0], (long)(i41 ^ 2));
+ }
+
@Test
public void testSideEffectAntishArray() throws Exception {
Integer i41 = Integer.valueOf(4141);
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedContext.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedContext.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedContext.java Sun Jul 3 17:26:59 2016
@@ -16,10 +16,12 @@
*/
package org.apache.commons.jexl3;
+import java.util.concurrent.Callable;
+
/**
* Exposes a synchronized call to a script and synchronizes access to get/set methods.
*/
-public class SynchronizedContext extends MapContext {
+public class SynchronizedContext extends MapContext implements JexlContext.AnnotationProcessor {
private final JexlContext context;
public SynchronizedContext(JexlContext ctxt) {
@@ -58,4 +60,15 @@ public class SynchronizedContext extends
}
}
+ @Override
+ public Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception {
+ if ("synchronized".equals(name)) {
+ final Object arg = args[0];
+ synchronized(arg) {
+ return statement.call();
+ }
+ }
+ throw new IllegalArgumentException("unknown annotation " + name);
+ }
+
}
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedOverloadsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedOverloadsTest.java?rev=1751163&r1=1751162&r2=1751163&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedOverloadsTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SynchronizedOverloadsTest.java Sun Jul 3 17:26:59 2016
@@ -53,6 +53,16 @@ public class SynchronizedOverloadsTest e
}
@Test
+ public void testSynchronized() throws Exception {
+ Map<String, Object> ns = new TreeMap<String, Object>();
+ JexlContext jc = new SynchronizedContext(new MapContext());
+ JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
+ JexlScript js0 = jexl.createScript("@synchronized(y) {return y.size(); }", "y");
+ Object size = js0.execute(jc, "foobar");
+ Assert.assertEquals(6, size);
+ }
+
+ @Test
public void testUnsafeMonitor() throws Exception {
SynchronizedArithmetic.Monitor monitor = new SynchronizedArithmetic.UnsafeMonitor();
Map<String, Object> foo = new TreeMap<String, Object>();
@@ -66,5 +76,9 @@ public class SynchronizedOverloadsTest e
Assert.assertEquals(10.0d, t);
Assert.assertTrue(monitor.isBalanced());
Assert.assertEquals(2, monitor.getCount());
+ t = js0.execute(jc, foo);
+ Assert.assertEquals(10.0d, t);
+ Assert.assertTrue(monitor.isBalanced());
+ Assert.assertEquals(4, monitor.getCount());
}
}