in velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMethod.java [143:263]
public Object execute(Object o, InternalContextAdapter context)
throws MethodInvocationException
{
try
{
rsvc.getLogContext().pushLogContext(this, uberInfo);
/*
* new strategy (strategery!) for introspection. Since we want
* to be thread- as well as context-safe, we *must* do it now,
* at execution time. There can be no in-node caching,
* but if we are careful, we can do it in the context.
*/
Object [] params = new Object[paramCount];
/*
* sadly, we do need recalc the values of the args, as this can
* change from visit to visit
*/
final Class<?>[] paramClasses =
paramCount > 0 ? new Class[paramCount] : EMPTY_CLASS_ARRAY;
for (int j = 0; j < paramCount; j++)
{
params[j] = jjtGetChild(j + 1).value(context);
if (params[j] != null)
{
paramClasses[j] = params[j].getClass();
}
}
VelMethod method = ClassUtils.getMethod(methodName, params, paramClasses,
o, context, this, strictRef);
// warn if method wasn't found (if strictRef is true, then ClassUtils did throw an exception)
if (o != null && method == null && logOnInvalid)
{
StringBuilder plist = new StringBuilder();
for (int i = 0; i < params.length; i++)
{
Class<?> param = paramClasses[i];
plist.append(param == null ? "null" : param.getName());
if (i < params.length - 1)
plist.append(", ");
}
log.debug("Object '{}' does not contain method {}({}) (or several ambiguous methods) at {}[line {}, column {}]", o.getClass().getName(), methodName, plist, getTemplateName(), getLine(), getColumn());
}
/*
* The parent class (typically ASTReference) uses the icache entry
* under 'this' key to distinguish a valid null result from a non-existent method.
* So update this dummy cache value if necessary.
*/
IntrospectionCacheData prevICD = context.icacheGet(this);
if (method == null)
{
if (prevICD != null)
{
context.icachePut(this, null);
}
return null;
}
else if (prevICD == null)
{
context.icachePut(this, new IntrospectionCacheData()); // no need to fill in its members
}
try
{
/*
* get the returned object. It may be null, and that is
* valid for something declared with a void return type.
* Since the caller is expecting something to be returned,
* as long as things are peachy, we can return an empty
* String so ASTReference() correctly figures out that
* all is well.
*/
Object obj = method.invoke(o, params);
if (obj == null)
{
if( method.getReturnType() == Void.TYPE)
{
return "";
}
}
return obj;
}
catch( InvocationTargetException ite )
{
return handleInvocationException(o, context, ite.getTargetException());
}
/* Can also be thrown by method invocation */
catch( IllegalArgumentException t )
{
return handleInvocationException(o, context, t);
}
/*
* pass through application level runtime exceptions
*/
catch( RuntimeException e )
{
throw e;
}
catch( Exception e )
{
String msg = "ASTMethod.execute() : exception invoking method '"
+ methodName + "' in " + o.getClass();
log.error(msg, e);
throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
}
}
finally
{
rsvc.getLogContext().popLogContext();
}
}