SFW-8224: distance can be used when computing method matches in ReflectiveMethodResolver
This commit is contained in:
@@ -102,6 +102,49 @@ public class ReflectionHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on {@link MethodInvoker.getTypeDifferenceWeight} but operates on TypeDescriptors.
|
||||
*/
|
||||
public static int getTypeDifferenceWeight(List<TypeDescriptor> paramTypes, List<TypeDescriptor> argTypes) {
|
||||
int result = 0;
|
||||
for (int i = 0,max=paramTypes.size(); i < max; i++) {
|
||||
TypeDescriptor argType = argTypes.get(i);
|
||||
TypeDescriptor paramType = paramTypes.get(i);
|
||||
if (argType==TypeDescriptor.NULL) {
|
||||
if (paramType.isPrimitive()) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
if (!ClassUtils.isAssignable(paramType.getClass(), argType.getClass())) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (argType != TypeDescriptor.NULL) {
|
||||
Class paramTypeClazz = paramType.getType();
|
||||
if (paramTypeClazz.isPrimitive()) {
|
||||
paramTypeClazz = Object.class;
|
||||
}
|
||||
Class superClass = argType.getClass().getSuperclass();
|
||||
while (superClass != null) {
|
||||
if (paramType.equals(superClass)) {
|
||||
result = result + 2;
|
||||
superClass = null;
|
||||
}
|
||||
else if (ClassUtils.isAssignable(paramTypeClazz, superClass)) {
|
||||
result = result + 2;
|
||||
superClass = superClass.getSuperclass();
|
||||
}
|
||||
else {
|
||||
superClass = null;
|
||||
}
|
||||
}
|
||||
if (paramTypeClazz.isInterface()) {
|
||||
result = result + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare argument arrays and return information about whether they match. A supplied type converter and
|
||||
|
||||
@@ -49,8 +49,29 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||
private static Method[] NO_METHODS = new Method[0];
|
||||
|
||||
private Map<Class<?>, MethodFilter> filters = null;
|
||||
|
||||
// Using distance will ensure a more accurate match is discovered,
|
||||
// more closely following the Java rules.
|
||||
private boolean useDistance = false;
|
||||
|
||||
|
||||
public ReflectiveMethodResolver() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructors allows the ReflectiveMethodResolver to be configured such that it will
|
||||
* use a distance computation to check which is the better of two close matches (when there
|
||||
* are multiple matches). Using the distance computation is intended to ensure matches
|
||||
* are more closely representative of what a Java compiler would do when taking into
|
||||
* account boxing/unboxing and whether the method candidates are declared to handle a
|
||||
* supertype of the type (of the argument) being passed in.
|
||||
* @param useDistance true if distance computation should be used when calculating matches
|
||||
*/
|
||||
public ReflectiveMethodResolver(boolean useDistance) {
|
||||
this.useDistance = useDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a method on a type. There are three kinds of match that might occur:
|
||||
* <ol>
|
||||
@@ -93,6 +114,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||
});
|
||||
|
||||
Method closeMatch = null;
|
||||
int closeMatchDistance = Integer.MAX_VALUE;
|
||||
int[] argsToConvert = null;
|
||||
Method matchRequiringConversion = null;
|
||||
boolean multipleOptions = false;
|
||||
@@ -121,7 +143,16 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||
return new ReflectiveMethodExecutor(method, null);
|
||||
}
|
||||
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
|
||||
closeMatch = method;
|
||||
if (!useDistance) {
|
||||
closeMatch = method;
|
||||
} else {
|
||||
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
|
||||
if (matchDistance<closeMatchDistance) {
|
||||
// this is a better match
|
||||
closeMatchDistance = matchDistance;
|
||||
closeMatch = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
|
||||
if (matchRequiringConversion != null) {
|
||||
|
||||
Reference in New Issue
Block a user