in freemarker-core/src/main/java/freemarker/ext/beans/ArgumentTypes.java [532:626]
private int isMethodInvocationConvertible(final Class<?> formal, final Class<?> actual) {
// Check for identity or widening reference conversion
if (formal.isAssignableFrom(actual) && actual != CharacterOrString.class) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (bugfixed) {
final Class<?> formalNP;
if (formal.isPrimitive()) {
if (actual == Null.class) {
return CONVERSION_DIFFICULTY_IMPOSSIBLE;
}
formalNP = ClassUtil.primitiveClassToBoxingClass(formal);
if (actual == formalNP) {
// Character and char, etc.
return CONVERSION_DIFFICULTY_REFLECTION;
}
} else { // formal is non-primitive
if (actual == Null.class) {
return CONVERSION_DIFFICULTY_REFLECTION;
}
formalNP = formal;
}
if (Number.class.isAssignableFrom(actual) && Number.class.isAssignableFrom(formalNP)) {
return OverloadedNumberUtil.getArgumentConversionPrice(actual, formalNP) == Integer.MAX_VALUE
? CONVERSION_DIFFICULTY_IMPOSSIBLE : CONVERSION_DIFFICULTY_REFLECTION;
} else if (formal.isArray()) {
// BeansWrapper method/constructor calls convert from List to array automatically
return List.class.isAssignableFrom(actual)
? CONVERSION_DIFFICULTY_FREEMARKER : CONVERSION_DIFFICULTY_IMPOSSIBLE;
} else if (actual.isArray() && formal.isAssignableFrom(List.class)) {
// BeansWrapper method/constructor calls convert from array to List automatically
return CONVERSION_DIFFICULTY_FREEMARKER;
} else if (actual == CharacterOrString.class
&& (formal.isAssignableFrom(String.class)
|| formal.isAssignableFrom(Character.class) || formal == char.class)) {
return CONVERSION_DIFFICULTY_FREEMARKER;
} else {
return CONVERSION_DIFFICULTY_IMPOSSIBLE;
}
} else { // if !bugfixed
// This non-bugfixed (backward-compatible, pre-2.3.21) branch:
// - Doesn't convert *to* non-primitive numerical types (unless the argument is a BigDecimal).
// (This is like in Java language, which also doesn't coerce to non-primitive numerical types.)
// - Doesn't support BigInteger conversions
// - Doesn't support NumberWithFallbackType-s and CharacterOrString-s. Those are only produced in bugfixed
// mode anyway.
// - Doesn't support conversion between array and List
if (formal.isPrimitive()) {
// Check for boxing with widening primitive conversion. Note that
// actual parameters are never primitives.
// It doesn't do the same with boxing types... that was a bug.
if (formal == Boolean.TYPE) {
return actual == Boolean.class
? CONVERSION_DIFFICULTY_REFLECTION : CONVERSION_DIFFICULTY_IMPOSSIBLE;
} else if (formal == Double.TYPE &&
(actual == Double.class || actual == Float.class ||
actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class)) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (formal == Integer.TYPE &&
(actual == Integer.class || actual == Short.class ||
actual == Byte.class)) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (formal == Long.TYPE &&
(actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class)) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (formal == Float.TYPE &&
(actual == Float.class || actual == Long.class ||
actual == Integer.class || actual == Short.class ||
actual == Byte.class)) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (formal == Character.TYPE) {
return actual == Character.class
? CONVERSION_DIFFICULTY_REFLECTION : CONVERSION_DIFFICULTY_IMPOSSIBLE;
} else if (formal == Byte.TYPE && actual == Byte.class) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (formal == Short.TYPE &&
(actual == Short.class || actual == Byte.class)) {
return CONVERSION_DIFFICULTY_REFLECTION;
} else if (BigDecimal.class.isAssignableFrom(actual) && ClassUtil.isNumerical(formal)) {
// Special case for BigDecimals as we deem BigDecimal to be
// convertible to any numeric type - either object or primitive.
// This can actually cause us trouble as this is a narrowing
// conversion, not widening.
return CONVERSION_DIFFICULTY_REFLECTION;
} else {
return CONVERSION_DIFFICULTY_IMPOSSIBLE;
}
} else {
return CONVERSION_DIFFICULTY_IMPOSSIBLE;
}
}
}