in velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/MethodMap.java [344:521]
private int compare(Type[] t1, Type[] t2)
{
boolean t1IsVararag = false;
boolean t2IsVararag = false;
boolean fixedLengths = false;
// compare lengths to handle comparisons where the size of the arrays
// doesn't match, but the methods are both applicable due to the fact
// that one is a varargs method
if (t1.length > t2.length)
{
int l2 = t2.length;
if (l2 == 0)
{
return MORE_SPECIFIC;
}
t2 = Arrays.copyOf(t2, t1.length);
Type itemType = TypeUtils.getArrayComponentType(t2[l2 - 1]);
/* if item class is null, then it implies the vaarg is #1
* (and receives an empty array)
*/
if (itemType == null)
{
/* by construct, we have c1.length = l2 + 1 */
t1IsVararag = true;
t2[t1.length - 1] = null;
}
else
{
t2IsVararag = true;
for (int i = l2 - 1; i < t1.length; ++i)
{
/* also overwrite the vaargs itself */
t2[i] = itemType;
}
}
fixedLengths = true;
}
else if (t2.length > t1.length)
{
int l1 = t1.length;
if (l1 == 0)
{
return LESS_SPECIFIC;
}
t1 = Arrays.copyOf(t1, t2.length);
Type itemType = TypeUtils.getArrayComponentType(t1[l1 - 1]);
/* if item class is null, then it implies the vaarg is #2
* (and receives an empty array)
*/
if (itemType == null)
{
/* by construct, we have c2.length = l1 + 1 */
t2IsVararag = true;
t1[t2.length - 1] = null;
}
else
{
t1IsVararag = true;
for (int i = l1 - 1; i < t2.length; ++i)
{
/* also overwrite the vaargs itself */
t1[i] = itemType;
}
}
fixedLengths = true;
}
/* ok, move on and compare those of equal lengths */
int fromC1toC2 = STRICTLY_CONVERTIBLE;
int fromC2toC1 = STRICTLY_CONVERTIBLE;
for(int i = 0; i < t1.length; ++i)
{
Class<?> c1 = t1[i] == null ? null : IntrospectionUtils.getTypeClass(t1[i]);
Class<?> c2 = t2[i] == null ? null : IntrospectionUtils.getTypeClass(t2[i]);
boolean last = !fixedLengths && (i == t1.length - 1);
if (t1[i] == null && t2[i] != null || t1[i] != null && t2[i] == null || !t1[i].equals(t2[i]))
{
if (t1[i] == null)
{
fromC2toC1 = NOT_CONVERTIBLE;
if (c2 != null && c2.isPrimitive())
{
fromC1toC2 = NOT_CONVERTIBLE;
}
}
else if (t2[i] == null)
{
fromC1toC2 = NOT_CONVERTIBLE;
if (c1 != null && c1.isPrimitive())
{
fromC2toC1 = NOT_CONVERTIBLE;
}
}
else
{
if (c1 != null)
{
switch (fromC1toC2)
{
case STRICTLY_CONVERTIBLE:
if (isStrictConvertible(t2[i], c1, last)) break;
fromC1toC2 = IMPLCITLY_CONVERTIBLE;
case IMPLCITLY_CONVERTIBLE:
if (isConvertible(t2[i], c1, last)) break;
fromC1toC2 = EXPLICITLY_CONVERTIBLE;
case EXPLICITLY_CONVERTIBLE:
if (isExplicitlyConvertible(t2[i], c1, last)) break;
fromC1toC2 = NOT_CONVERTIBLE;
}
}
else if (fromC1toC2 > NOT_CONVERTIBLE)
{
fromC1toC2 = TypeUtils.isAssignable(t1[i], t2[i]) ?
Math.min(fromC1toC2, IMPLCITLY_CONVERTIBLE) :
NOT_CONVERTIBLE;
}
if (c2 != null)
{
switch (fromC2toC1)
{
case STRICTLY_CONVERTIBLE:
if (isStrictConvertible(t1[i], c2, last)) break;
fromC2toC1 = IMPLCITLY_CONVERTIBLE;
case IMPLCITLY_CONVERTIBLE:
if (isConvertible(t1[i], c2, last)) break;
fromC2toC1 = EXPLICITLY_CONVERTIBLE;
case EXPLICITLY_CONVERTIBLE:
if (isExplicitlyConvertible(t1[i], c2, last)) break;
fromC2toC1 = NOT_CONVERTIBLE;
}
}
else if (fromC2toC1 > NOT_CONVERTIBLE)
{
fromC2toC1 = TypeUtils.isAssignable(t2[i], t1[i]) ?
Math.min(fromC2toC1, IMPLCITLY_CONVERTIBLE) :
NOT_CONVERTIBLE;
}
}
}
}
if (fromC1toC2 == NOT_CONVERTIBLE && fromC2toC1 == NOT_CONVERTIBLE)
{
/*
* Incomparable due to cross-assignable arguments (i.e.
* foo(String, Foo) vs. foo(Foo, String))
*/
return INCOMPARABLE;
}
if (fromC1toC2 > fromC2toC1)
{
return MORE_SPECIFIC;
}
else if (fromC2toC1 > fromC1toC2)
{
return LESS_SPECIFIC;
}
else
{
/*
* If one method accepts varargs and the other does not,
* call the non-vararg one more specific.
*/
boolean last1Array = t1IsVararag || !fixedLengths && TypeUtils.isArrayType (t1[t1.length - 1]);
boolean last2Array = t2IsVararag || !fixedLengths && TypeUtils.isArrayType(t2[t2.length - 1]);
if (last1Array && !last2Array)
{
return LESS_SPECIFIC;
}
if (!last1Array && last2Array)
{
return MORE_SPECIFIC;
}
}
return EQUIVALENT;
}