in velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectionUtils.java [154:253]
public static boolean isMethodInvocationConvertible(Type formal,
Class<?> actual,
boolean possibleVarArg)
{
Class<?> formalClass = getTypeClass(formal);
if (formalClass != null)
{
/* if it's a null, it means the arg was null */
if (actual == null)
{
return !formalClass.isPrimitive();
}
/* Check for identity or widening reference conversion */
if (formalClass.isAssignableFrom(actual))
{
return true;
}
/* 2.0: Since MethodMap's comparison functions now use this method with potentially reversed arguments order,
* actual can be a primitive type. */
/* Check for boxing */
if (!formalClass.isPrimitive() && actual.isPrimitive())
{
Class<?> boxed = boxingMap.get(actual);
if (boxed != null && (boxed == formalClass || formalClass.isAssignableFrom(boxed))) return true;
}
if (formalClass.isPrimitive())
{
if (actual.isPrimitive())
{
/* check for widening primitive conversion */
if (formalClass == Short.TYPE && actual == Byte.TYPE)
return true;
if (formalClass == Integer.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE))
return true;
if (formalClass == Long.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE || actual == Integer.TYPE))
return true;
if (formalClass == Float.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE || actual == Integer.TYPE ||
actual == Long.TYPE))
return true;
if (formalClass == Double.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE || actual == Integer.TYPE ||
actual == Long.TYPE || actual == Float.TYPE))
return true;
} else
{
/* Check for unboxing with widening primitive conversion. */
if (formalClass == Boolean.TYPE && actual == Boolean.class)
return true;
if (formalClass == Character.TYPE && actual == Character.class)
return true;
if (formalClass == Byte.TYPE && actual == Byte.class)
return true;
if (formalClass == Short.TYPE && (actual == Short.class || actual == Byte.class))
return true;
if (formalClass == Integer.TYPE && (actual == Integer.class || actual == Short.class ||
actual == Byte.class))
return true;
if (formalClass == Long.TYPE && (actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class))
return true;
if (formalClass == Float.TYPE && (actual == Float.class || actual == Long.class ||
actual == Integer.class || actual == Short.class || actual == Byte.class))
return true;
if (formalClass == Double.TYPE && (actual == Double.class || actual == Float.class ||
actual == Long.class || actual == Integer.class || actual == Short.class ||
actual == Byte.class))
return true;
}
}
/* Check for vararg conversion. */
if (possibleVarArg && formalClass.isArray())
{
if (actual.isArray())
{
actual = actual.getComponentType();
}
return isMethodInvocationConvertible(formalClass.getComponentType(),
actual, false);
}
return false;
}
else
{
// no distinction between strict and implicit, not a big deal in this case
if (TypeUtils.isAssignable(actual, formal))
{
return true;
}
return possibleVarArg && TypeUtils.isArrayType(formal) &&
TypeUtils.isAssignable(actual, TypeUtils.getArrayComponentType(formal));
}
}