in commons-digester3-core/src/main/java/org/apache/commons/digester3/CallMethodRule.java [308:434]
public void end( final String namespace, final String name )
throws Exception
{
// Retrieve or construct the parameter values array
Object[] parameters;
if ( paramCount > 0 )
{
parameters = getDigester().popParams();
if ( getDigester().getLogger().isTraceEnabled() )
{
for ( int i = 0, size = parameters.length; i < size; i++ )
{
getDigester().getLogger().trace( format( "[CallMethodRule]{%s} parameters[%s]=%s",
getDigester().getMatch(),
i,
parameters[i] ) );
}
}
// In the case where the target method takes a single parameter
// and that parameter does not exist (the CallParamRule never
// executed or the CallParamRule was intended to set the parameter
// from an attribute but the attribute wasn't present etc) then
// skip the method call.
//
// This is useful when a class has a "default" value that should
// only be overridden if data is present in the XML. I don't
// know why this should only apply to methods taking *one*
// parameter, but it always has been so we can't change it now.
if ( paramCount == 1 && parameters[0] == null )
{
return;
}
}
else if ( paramTypes != null && paramTypes.length != 0 )
{
// Having paramCount == 0 and paramTypes.length == 1 indicates
// that we have the special case where the target method has one
// parameter being the body text of the current element.
// There is no body text included in the source XML file,
// so skip the method call
if ( bodyText == null )
{
return;
}
parameters = new Object[] { bodyText };
}
else
{
// When paramCount is zero and paramTypes.length is zero it
// means that we truly are calling a method with no parameters.
// Nothing special needs to be done here.
parameters = new Object[0];
paramTypes = new Class<?>[0];
}
// Construct the parameter values array we will need
// We only do the conversion if the param value is a String and
// the specified paramType is not String.
final Object[] paramValues = new Object[paramTypes.length];
for ( int i = 0; i < paramTypes.length; i++ )
{
// convert nulls and convert stringy parameters
// for non-stringy param types
if ( parameters[i] == null
|| parameters[i] instanceof String && !String.class.isAssignableFrom( paramTypes[i] ) )
{
paramValues[i] = convert( (String) parameters[i], paramTypes[i] );
}
else
{
paramValues[i] = parameters[i];
}
}
// Determine the target object for the method call
Object target;
if ( targetOffset >= 0 )
{
target = getDigester().peek( targetOffset );
}
else
{
target = getDigester().peek( getDigester().getCount() + targetOffset );
}
if ( target == null )
{
throw new SAXException( format( "[CallMethodRule]{%s} Call target is null (targetOffset=%s, stackdepth=%s)",
getDigester().getMatch(), targetOffset, getDigester().getCount() ) );
}
// Invoke the required method on the top object
if ( getDigester().getLogger().isDebugEnabled() )
{
final Formatter formatter =
new Formatter().format( "[CallMethodRule]{%s} Call %s.%s(",
getDigester().getMatch(),
target.getClass().getName(),
methodName );
for ( int i = 0; i < paramValues.length; i++ )
{
formatter.format( "%s%s/%s", i > 0 ? ", " : "", paramValues[i], paramTypes[i].getName() );
}
formatter.format( ")" );
getDigester().getLogger().debug( formatter.toString() );
}
Object result;
if ( useExactMatch )
{
// invoke using exact match
result = invokeExactMethod( target, methodName, paramValues, paramTypes );
}
else
{
// invoke using fuzzier match
result = invokeMethod( target, methodName, paramValues, paramTypes );
}
processMethodCallResult( result );
}