use of org.apache.commons.jexl3.introspection.JexlMethod in project commons-jexl by apache.
the class Interpreter method visit.
@Override
protected Object visit(final ASTConstructorNode node, final Object data) {
if (isCancelled()) {
throw new JexlException.Cancel(node);
}
// first child is class or class name
final Object target = node.jjtGetChild(0).jjtAccept(this, data);
// get the ctor args
final int argc = node.jjtGetNumChildren() - 1;
Object[] argv = new Object[argc];
for (int i = 0; i < argc; i++) {
argv[i] = node.jjtGetChild(i + 1).jjtAccept(this, data);
}
try {
final boolean cacheable = cache;
// attempt to reuse last funcall cached in volatile JexlNode.value
if (cacheable) {
final Object cached = node.jjtGetValue();
if (cached instanceof Funcall) {
final Object eval = ((Funcall) cached).tryInvoke(this, null, target, argv);
if (JexlEngine.TRY_FAILED != eval) {
return eval;
}
}
}
boolean narrow = false;
JexlMethod ctor = null;
Funcall funcall = null;
while (true) {
// try as stated
ctor = uberspect.getConstructor(target, argv);
if (ctor != null) {
if (cacheable && ctor.isCacheable()) {
funcall = new Funcall(ctor, narrow);
}
break;
}
// try with prepending context as first argument
final Object[] nargv = callArguments(context, narrow, argv);
ctor = uberspect.getConstructor(target, nargv);
if (ctor != null) {
if (cacheable && ctor.isCacheable()) {
funcall = new ContextualCtor(ctor, narrow);
}
argv = nargv;
break;
}
// attempt to narrow the parameters and if this succeeds, try again in next loop
if (!narrow && arithmetic.narrowArguments(argv)) {
narrow = true;
continue;
}
// we are done trying
break;
}
// we have either evaluated and returned or might have found a ctor
if (ctor != null) {
final Object eval = ctor.invoke(target, argv);
// cache executor in volatile JexlNode.value
if (funcall != null) {
node.jjtSetValue(funcall);
}
return eval;
}
final String tstr = target != null ? target.toString() : "?";
return unsolvableMethod(node, tstr, argv);
} catch (final JexlException.Method xmethod) {
throw xmethod;
} catch (final Exception xany) {
final String tstr = target != null ? target.toString() : "?";
throw invocationException(node, tstr, xany);
}
}
use of org.apache.commons.jexl3.introspection.JexlMethod in project commons-jexl by apache.
the class Engine method doCreateInstance.
/**
* Creates a new instance of an object using the most appropriate constructor
* based on the arguments.
* @param clazz the class to instantiate
* @param args the constructor arguments
* @return the created object instance or null on failure when silent
*/
protected Object doCreateInstance(final Object clazz, final Object... args) {
JexlException xjexl = null;
Object result = null;
final JexlInfo info = debug ? createInfo() : null;
try {
JexlMethod ctor = uberspect.getConstructor(clazz, args);
if (ctor == null && arithmetic.narrowArguments(args)) {
ctor = uberspect.getConstructor(clazz, args);
}
if (ctor != null) {
result = ctor.invoke(clazz, args);
} else {
xjexl = new JexlException.Method(info, clazz.toString(), args);
}
} catch (final JexlException xany) {
xjexl = xany;
} catch (final Exception xany) {
xjexl = new JexlException.Method(info, clazz.toString(), args, xany);
}
if (xjexl != null) {
if (silent) {
if (logger.isWarnEnabled()) {
logger.warn(xjexl.getMessage(), xjexl.getCause());
}
return null;
}
throw xjexl.clean();
}
return result;
}
use of org.apache.commons.jexl3.introspection.JexlMethod in project commons-jexl by apache.
the class Engine method invokeMethod.
@Override
public Object invokeMethod(final Object obj, final String meth, final Object... args) {
JexlException xjexl = null;
Object result = null;
final JexlInfo info = debug ? createInfo() : null;
try {
JexlMethod method = uberspect.getMethod(obj, meth, args);
if (method == null && arithmetic.narrowArguments(args)) {
method = uberspect.getMethod(obj, meth, args);
}
if (method != null) {
result = method.invoke(obj, args);
} else {
xjexl = new JexlException.Method(info, meth, args);
}
} catch (final JexlException xany) {
xjexl = xany;
} catch (final Exception xany) {
xjexl = new JexlException.Method(info, meth, args, xany);
}
if (xjexl != null) {
if (!silent) {
throw xjexl.clean();
}
if (logger.isWarnEnabled()) {
logger.warn(xjexl.getMessage(), xjexl.getCause());
}
}
return result;
}
use of org.apache.commons.jexl3.introspection.JexlMethod in project commons-jexl by apache.
the class Operators method tryOverload.
/**
* Attempts to call an operator.
* <p>
* This takes care of finding and caching the operator method when appropriate
* @param node the syntactic node
* @param operator the operator
* @param args the arguments
* @return the result of the operator evaluation or TRY_FAILED
*/
protected Object tryOverload(final JexlNode node, final JexlOperator operator, final Object... args) {
if (operators != null && operators.overloads(operator)) {
final JexlArithmetic arithmetic = interpreter.arithmetic;
final boolean cache = interpreter.cache;
try {
if (cache) {
final Object cached = node.jjtGetValue();
if (cached instanceof JexlMethod) {
final JexlMethod me = (JexlMethod) cached;
final Object eval = me.tryInvoke(operator.getMethodName(), arithmetic, args);
if (!me.tryFailed(eval)) {
return eval;
}
}
}
final JexlMethod vm = operators.getOperator(operator, args);
if (vm != null && !isArithmetic(vm)) {
final Object result = vm.invoke(arithmetic, args);
if (cache) {
node.jjtSetValue(vm);
}
return result;
}
} catch (final Exception xany) {
return interpreter.operatorError(node, operator, xany);
}
}
return JexlEngine.TRY_FAILED;
}
use of org.apache.commons.jexl3.introspection.JexlMethod in project commons-jexl by apache.
the class Operators method contains.
/**
* The 'match'/'in' operator implementation.
* <p>
* Note that 'x in y' or 'x matches y' means 'y contains x' ;
* the JEXL operator arguments order syntax is the reverse of this method call.
* </p>
* @param node the node
* @param op the calling operator, =~ or !~
* @param right the left operand
* @param left the right operand
* @return true if left matches right, false otherwise
*/
protected boolean contains(final JexlNode node, final String op, final Object left, final Object right) {
final JexlArithmetic arithmetic = interpreter.arithmetic;
final JexlUberspect uberspect = interpreter.uberspect;
try {
// try operator overload
final Object result = tryOverload(node, JexlOperator.CONTAINS, left, right);
if (result instanceof Boolean) {
return (Boolean) result;
}
// use arithmetic / pattern matching ?
final Boolean matched = arithmetic.contains(left, right);
if (matched != null) {
return matched;
}
// try a contains method (duck type set)
try {
final Object[] argv = { right };
JexlMethod vm = uberspect.getMethod(left, "contains", argv);
if (returnsBoolean(vm)) {
return (Boolean) vm.invoke(left, argv);
}
if (arithmetic.narrowArguments(argv)) {
vm = uberspect.getMethod(left, "contains", argv);
if (returnsBoolean(vm)) {
return (Boolean) vm.invoke(left, argv);
}
}
} catch (final Exception e) {
throw new JexlException(node, op + " error", e);
}
// defaults to equal
return arithmetic.equals(left, right);
} catch (final ArithmeticException xrt) {
throw new JexlException(node, op + " error", xrt);
}
}
Aggregations