You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2019/05/13 13:04:43 UTC
[commons-jexl] branch master updated: JEXL-299: added argument
classes to method signature in Exception reporting
This is an automated email from the ASF dual-hosted git repository.
henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/master by this push:
new fb59841 JEXL-299: added argument classes to method signature in Exception reporting
fb59841 is described below
commit fb598419c2c6b3997b60b3b1c022a7a309a26220
Author: henrib <he...@apache.org>
AuthorDate: Mon May 13 15:03:57 2019 +0200
JEXL-299: added argument classes to method signature in Exception reporting
---
.../org/apache/commons/jexl3/JexlException.java | 137 +++++++++++++++++++--
.../apache/commons/jexl3/internal/Interpreter.java | 34 +----
.../commons/jexl3/internal/InterpreterBase.java | 46 ++++++-
3 files changed, 172 insertions(+), 45 deletions(-)
diff --git a/src/main/java/org/apache/commons/jexl3/JexlException.java b/src/main/java/org/apache/commons/jexl3/JexlException.java
index 63ed9c6..1b23b17 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlException.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlException.java
@@ -97,7 +97,7 @@ public class JexlException extends RuntimeException {
public JexlInfo getInfo() {
return getInfo(mark, info);
}
-
+
/**
* Creates a string builder pre-filled with common error information (if possible).
*
@@ -176,13 +176,12 @@ public class JexlException extends RuntimeException {
* @return the cause
*/
private static Throwable unwrap(Throwable xthrow) {
- if (xthrow instanceof InvocationTargetException) {
- return xthrow.getCause();
- } else if (xthrow instanceof UndeclaredThrowableException) {
+ if (xthrow instanceof TryFailed
+ || xthrow instanceof InvocationTargetException
+ || xthrow instanceof UndeclaredThrowableException) {
return xthrow.getCause();
- } else {
- return xthrow;
}
+ return xthrow;
}
/**
@@ -647,36 +646,114 @@ public class JexlException extends RuntimeException {
*
* @param node the offending ASTnode
* @param name the method name
+ * @deprecated as of 3.2, use call with method arguments
*/
+ @Deprecated
public Method(JexlNode node, String name) {
- super(node, name);
+ this(node, name, null);
}
-
+
/**
* Creates a new Method exception instance.
*
* @param info the location information
* @param name the unknown method
* @param cause the exception causing the error
+ * @deprecated as of 3.2, use call with method arguments
*/
+ @Deprecated
public Method(JexlInfo info, String name, Throwable cause) {
- super(info, name, cause);
+ this(info, name, null, cause);
+ }
+
+ /**
+ * Creates a new Method exception instance.
+ *
+ * @param node the offending ASTnode
+ * @param name the method name
+ * @param args the method arguments
+ * @since 3.2
+ */
+ public Method(JexlNode node, String name, Object[] args) {
+ super(node, methodSignature(name, args));
+ }
+
+ /**
+ * Creates a new Method exception instance.
+ *
+ * @param info the location information
+ * @param name the method name
+ * @param args the method arguments
+ * @since 3.2
+ */
+ public Method(JexlInfo info, String name, Object[] args) {
+ this(info, name, args, null);
}
+
+ /**
+ * Creates a new Method exception instance.
+ *
+ * @param info the location information
+ * @param name the method name
+ * @param cause the exception causing the error
+ * @param args the method arguments
+ * @since 3.2
+ */
+ public Method(JexlInfo info, String name, Object[] args, Throwable cause) {
+ super(info, methodSignature(name, args), cause);
+ }
+
/**
* @return the method name
*/
public String getMethod() {
+ String signature = getMethodSignature();
+ int lparen = signature.indexOf('(');
+ return lparen > 0? signature.substring(0, lparen) : signature;
+ }
+
+ /**
+ * @return the method signature
+ * @since 3.2
+ */
+ public String getMethodSignature() {
return super.detailedMessage();
}
@Override
protected String detailedMessage() {
- return "unsolvable function/method '" + getMethod() + "'";
+ return "unsolvable function/method '" + getMethodSignature() + "'";
}
}
/**
+ * Creates a signed-name for a given method name and arguments.
+ * @param name the method name
+ * @param args the method arguments
+ * @return a suitable signed name
+ */
+ private static String methodSignature(String name, Object[] args) {
+ if (args != null && args.length > 0) {
+ StringBuilder strb = new StringBuilder(name);
+ strb.append('(');
+ for (int a = 0; a < args.length; ++a) {
+ if (a > 0) {
+ strb.append(", ");
+ }
+ Class<?> clazz = args[a] == null ? Object.class : args[a].getClass();
+ strb.append(clazz.getSimpleName());
+ if (clazz.isArray()) {
+ strb.append("[]");
+ }
+ }
+ strb.append(')');
+ return strb.toString();
+ }
+ return name;
+ }
+
+ /**
* Generates a message for a unsolvable method error.
*
* @param node the node where the error occurred
@@ -684,9 +761,21 @@ public class JexlException extends RuntimeException {
* @return the error message
*/
public static String methodError(JexlNode node, String method) {
+ return methodError(node, method, null);
+ }
+
+ /**
+ * Generates a message for a unsolvable method error.
+ *
+ * @param node the node where the error occurred
+ * @param method the method name
+ * @param args the method arguments
+ * @return the error message
+ */
+ public static String methodError(JexlNode node, String method, Object[] args) {
StringBuilder msg = errorAt(node);
msg.append("unsolvable function/method '");
- msg.append(method);
+ msg.append(methodSignature(method, args));
msg.append('\'');
return msg.toString();
}
@@ -861,6 +950,32 @@ public class JexlException extends RuntimeException {
}
/**
+ * Thrown when method/ctor invocation fails.
+ * <p>These wrap InvocationTargetException as runtime exception
+ * allowing to go through without signature modifications.
+ * @since 3.2
+ */
+ public static class TryFailed extends JexlException {
+ /**
+ * Creates a new instance.
+ * @param xany the original invocation target exception
+ */
+ private TryFailed(InvocationTargetException xany) {
+ super((JexlInfo) null, "tryFailed", xany.getCause());
+ }
+ }
+
+ /**
+ * Wrap an invocation exception.
+ * <p>Return the cause if it is already a JexlException.
+ * @param xinvoke the invocation exception
+ * @return a JexlException
+ */
+ public static RuntimeException tryFailed(InvocationTargetException xinvoke) {
+ return new JexlException.TryFailed(xinvoke); // fail
+ }
+
+ /**
* Detailed info message about this error.
* Format is "debug![begin,end]: string \n msg" where:
*
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 7844369..82ff17d 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -123,8 +123,6 @@ import java.util.concurrent.Callable;
public class Interpreter extends InterpreterBase {
/** The operators evaluation delegate. */
protected final Operators operators;
- /** Cache executors. */
- protected final boolean cache;
/** Frame height. */
protected int fp = 0;
/** Symbol values. */
@@ -151,7 +149,6 @@ public class Interpreter extends InterpreterBase {
protected Interpreter(Engine engine, JexlContext aContext, Scope.Frame eFrame) {
super(engine, aContext);
this.operators = new Operators(this);
- this.cache = jexl.cache != null;
this.frame = eFrame;
if (this.context instanceof JexlContext.NamespaceResolver) {
ns = ((JexlContext.NamespaceResolver) context);
@@ -170,7 +167,6 @@ public class Interpreter extends InterpreterBase {
protected Interpreter(Interpreter ii, JexlArithmetic jexla) {
super(ii, jexla);
operators = ii.operators;
- cache = ii.cache;
frame = ii.frame;
ns = ii.ns;
functions = ii.functions;
@@ -1078,28 +1074,6 @@ public class Interpreter extends InterpreterBase {
}
/**
- * Checks whether a reference child node holds a local variable reference.
- * @param node the reference node
- * @param which the child we are checking
- * @return true if child is local variable, false otherwise
- */
- protected boolean isLocalVariable(ASTReference node, int which) {
- return (node.jjtGetNumChildren() > which
- && node.jjtGetChild(which) instanceof ASTIdentifier
- && ((ASTIdentifier) node.jjtGetChild(which)).getSymbol() >= 0);
- }
-
- /**
- * Checks whether a reference child node holds a function call.
- * @param node the reference node
- * @return true if child is function call, false otherwise
- */
- protected boolean isFunctionCall(ASTReference node) {
- return (node.jjtGetNumChildren() > 0
- && node.jjtGetChild(0) instanceof ASTFunctionNode);
- }
-
- /**
* Evaluates an access identifier based on the 2 main implementations;
* static (name or numbered identifier) or dynamic (jxlt).
* @param node the identifier access node
@@ -1679,7 +1653,7 @@ public class Interpreter extends InterpreterBase {
// attempt to narrow the parameters and if this succeeds, try again in next loop
if (!narrow && arithmetic.narrowArguments(argv)) {
narrow = true;
- continue;
+ // continue;
} else {
break;
}
@@ -1687,7 +1661,9 @@ public class Interpreter extends InterpreterBase {
// we have either evaluated and returned or no method was found
return node.isSafeLhs(jexl.safe)
? null
- : unsolvableMethod(node, methodName);
+ : unsolvableMethod(node, methodName, argv);
+ } catch (JexlException.TryFailed xany) {
+ throw invocationException(node, methodName, xany.getCause());
} catch (JexlException xthru) {
throw xthru;
} catch (Exception xany) {
@@ -1762,7 +1738,7 @@ public class Interpreter extends InterpreterBase {
return eval;
}
String tstr = target != null ? target.toString() : "?";
- return unsolvableMethod(node, tstr);
+ return unsolvableMethod(node, tstr, argv);
} catch (JexlException.Method xmethod) {
throw xmethod;
} catch (Exception xany) {
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 7c2f615..3c473c2 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
@@ -50,6 +50,8 @@ public abstract class InterpreterBase extends ParserVisitor {
protected final JexlArithmetic arithmetic;
/** The context to store/retrieve variables. */
protected final JexlContext context;
+ /** Cache executors. */
+ protected final boolean cache;
/** Cancellation support. */
protected volatile boolean cancelled = false;
/** Empty parameters for method matching. */
@@ -65,6 +67,7 @@ public abstract class InterpreterBase extends ParserVisitor {
this.logger = jexl.logger;
this.uberspect = jexl.uberspect;
this.context = aContext != null ? aContext : Engine.EMPTY_CONTEXT;
+ this.cache = engine.cache != null;
JexlArithmetic jexla = jexl.arithmetic;
this.arithmetic = jexla.options(context);
if (arithmetic != jexla && !arithmetic.getClass().equals(jexla.getClass())) {
@@ -85,6 +88,7 @@ public abstract class InterpreterBase extends ParserVisitor {
uberspect = ii.uberspect;
context = ii.context;
arithmetic = ii.arithmetic;
+ cache = ii.cache;
}
@@ -219,10 +223,21 @@ public abstract class InterpreterBase extends ParserVisitor {
* @return throws JexlException if strict and not silent, null otherwise
*/
protected Object unsolvableMethod(JexlNode node, String method) {
+ return unsolvableMethod(node, method, null);
+ }
+
+ /**
+ * Triggered when a method can not be resolved.
+ * @param node the node where the error originated from
+ * @param method the method name
+ * @param args the method arguments
+ * @return throws JexlException if strict and not silent, null otherwise
+ */
+ protected Object unsolvableMethod(JexlNode node, String method, Object[] args) {
if (isStrictEngine()) {
- throw new JexlException.Method(node, method);
+ throw new JexlException.Method(node, method, args);
} else if (logger.isDebugEnabled()) {
- logger.debug(JexlException.methodError(node, method));
+ logger.debug(JexlException.methodError(node, method, args));
}
return null;
}
@@ -245,6 +260,28 @@ public abstract class InterpreterBase extends ParserVisitor {
}
/**
+ * Checks whether a reference child node holds a local variable reference.
+ * @param node the reference node
+ * @param which the child we are checking
+ * @return true if child is local variable, false otherwise
+ */
+ protected boolean isLocalVariable(ASTReference node, int which) {
+ return (node.jjtGetNumChildren() > which
+ && node.jjtGetChild(which) instanceof ASTIdentifier
+ && ((ASTIdentifier) node.jjtGetChild(which)).getSymbol() >= 0);
+ }
+
+ /**
+ * Checks whether a reference child node holds a function call.
+ * @param node the reference node
+ * @return true if child is function call, false otherwise
+ */
+ protected boolean isFunctionCall(ASTReference node) {
+ return (node.jjtGetNumChildren() > 0
+ && node.jjtGetChild(0) instanceof ASTFunctionNode);
+ }
+
+ /**
* Pretty-prints a failing property (de)reference.
* <p>Used by calls to unsolvableProperty(...).</p>
* @param node the property node
@@ -320,7 +357,7 @@ public abstract class InterpreterBase extends ParserVisitor {
* @param xany the cause
* @return a JexlException that will be thrown
*/
- protected JexlException invocationException(JexlNode node, String methodName, Exception xany) {
+ protected JexlException invocationException(JexlNode node, String methodName, Throwable xany) {
Throwable cause = xany.getCause();
if (cause instanceof JexlException) {
return (JexlException) cause;
@@ -653,8 +690,7 @@ public abstract class InterpreterBase extends ParserVisitor {
}
return eval;
}
- return unsolvableMethod(node, mname);
+ return unsolvableMethod(node, mname, argv);
}
}
-
}