Using reflection to determine method overloading
A thread on the DWR mailing list about properly detected overloaded methods with covariant types in JDK5 got me curious. So I put together some quick code to determine if one method overloads another. It works for covariant types, but I didn't add support for generics. I'm not sure how much more work that would be.
Full source code follows. Feel free to use it if you like it, just leave the attribution. I'm sure there could be more testing and some optimization done, also. I would also be very curious to know if anyone else has had to do something similiar.
Here's the main util class that does the work:
-
package com.robsanheim.sandbox.reflection.overloading;
-
-
import java.lang.reflect.Method;
-
import java.util.Arrays;
-
-
/**
-
* @author Rob Sanheim
-
*
-
* A utility to check if one method is overloading another. Note that this
-
* utility does not take into account generics at all, but it should work
-
* correctly for covariant return types.
-
* @link <a * href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#227768">the
-
* JLS</a> for information on overloading
-
*
-
* TODO change to allow parameters to isOverloaded be ordered any way, and make this
-
* class figure out which is the "higher level" method
-
*
-
* TODO change to support generics, particularily the nasty case where an
-
* overloaded or overridden method uses generics and the base method does not -
-
* see <a * href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8.3">JLS
-
* again</a>
-
*/
-
public class OverloadUtil {
-
/**
-
* Check two methods reflectively to see if one is overloading the other
-
* Note that the parameter ordering is important if one method is higher in
-
* the class hiearchy then the other. If this is the case, make sure the
-
* method higher up in the chain is the first parameter. Otherwise, the
-
* ordering does not matter.
-
*
-
* @param higher
-
* method
-
* @param lower
-
* method
-
* @return
-
*/
-
if (namesAreEqual(higher, lower) && returnTypesAreEqualOrCovariant(higher, lower)
-
&& isNotInterfaceImplementation(higher, lower) && isNotOverridden(higher, lower)) {
-
return true;
-
-
} else {
-
return false;
-
}
-
}
-
-
if (isOverridden(higher, lower)) {
-
return false;
-
} else {
-
return true;
-
}
-
}
-
-
/**
-
* @param higher
-
* @param lower
-
* @return true if lower overrides higher
-
*/
-
return declaringClassIsAssignableFrom(higher, lower) && declaringClassIsNotAnInterface(higher)
-
&& parametersAreEqual(higher, lower);
-
}
-
-
/**
-
* @param first
-
* @param second
-
* @return true if the first method's declaring class is assignable from the
-
* second
-
*/
-
return first.getDeclaringClass().isAssignableFrom(second.getDeclaringClass());
-
-
}
-
-
/**
-
* We have to make sure we don't mistake standard interface implementation
-
* (where first method is on an interface and the params are equal) for
-
* overloading.
-
*
-
* @param higher
-
* @param lower
-
* @return
-
*/
-
return !(declaringClassIsAnInterface(higher) && parametersAreEqual(higher, lower));
-
}
-
-
/**
-
* check deep equality on parameters of two methods
-
*
-
* @param first
-
* @param second
-
* @return
-
*/
-
}
-
-
/**
-
* @param higher
-
* @param lower
-
* @return true if return types are equal or covariants
-
*/
-
return (declaringClassIsAssignableFrom(higher, lower) || higher.getReturnType().equals(lower.getReturnType()));
-
}
-
-
/**
-
* @param first
-
* @param second
-
* @return true if the names of the two methods are equal
-
*/
-
return first.getName().equals(second.getName());
-
}
-
-
return method.getDeclaringClass().isInterface();
-
}
-
-
return !declaringClassIsAnInterface(method);
-
}
-
-
}
Test case:
-
package com.robsanheim.sandbox.reflection.overloading;
-
-
import java.lang.reflect.Method;
-
-
import junit.framework.TestCase;
-
-
/**
-
* @author Rob Sanheim
-
*
-
* Test OverloadUtil
-
* Unless otherwise noted, we cannot assume that isOverloaded(x, y) == isOverloaded(y, x)
-
*/
-
public class OverloadUtilTest extends TestCase {
-
private static final Class[] NO_PARAMETERS = null;
-
// fixtures
-
private Method returnsObjectNoParametersDifferentName = getMethod(ConcreteClass.class, ANOTHER_METHOD,
-
NO_PARAMETERS);
-
private Method returnsStringNoParametersOnSubClass = getMethod(SubClass.class, METHOD, NO_PARAMETERS);
-
private Method returnsObjectNoParametersOnInterfaceType = getMethod(Interface.class, METHOD, NO_PARAMETERS);
-
-
/**
-
* This type of test should be reversible
-
*
-
* @throws Exception
-
*/
-
assertTrue(OverloadUtil.isOverloaded(returnsStringNoParameters, returnsStringOneParameter));
-
assertTrue(OverloadUtil.isOverloaded(returnsStringOneParameter, returnsStringNoParameters));
-
}
-
-
assertTrue(OverloadUtil.isOverloaded(returnsObjectNoParametersOnInterfaceType, returnsStringOneParameter));
-
}
-
-
assertFalse(OverloadUtil.isOverloaded(returnsObjectNoParametersOnInterfaceType, returnsStringNoParameters));
-
}
-
-
/**
-
* This type of test should be reversible
-
*
-
* @throws Exception
-
*/
-
assertFalse(OverloadUtil.isOverloaded(returnsStringNoParameters, returnsObjectNoParametersDifferentName));
-
assertFalse(OverloadUtil.isOverloaded(returnsStringOneParameter, returnsObjectNoParametersDifferentName));
-
}
-
-
assertFalse(OverloadUtil.isOverloaded(returnsObjectNoParametersOnInterfaceType,
-
returnsObjectNoParametersDifferentName));
-
}
-
-
assertFalse(OverloadUtil.isOverloaded(returnsStringNoParameters, returnsStringNoParametersOnSubClass));
-
}
-
-
assertTrue(OverloadUtil.isOverloaded(returnsObjectNoParametersOnInterfaceType,
-
returnsObjectThreeParametersOnSubClass));
-
}
-
-
/**
-
* This type of test should be reversible
-
*
-
* @throws Exception
-
*/
-
assertTrue(OverloadUtil.isOverloaded(returnsStringNoParametersOnSubClass,
-
returnsObjectThreeParametersOnSubClass));
-
assertTrue(OverloadUtil.isOverloaded(returnsObjectThreeParametersOnSubClass,
-
returnsStringNoParametersOnSubClass));
-
}
-
-
assertTrue(OverloadUtil.isOverloaded(returnsStringOneParameter, returnsObjectThreeParametersOnSubClass));
-
}
-
-
public void testMethodOnSubclassDoesNotOverloadMethodOfDifferentNameOnSuperClass() throws Exception {
-
assertFalse(OverloadUtil.isOverloaded(returnsObjectNoParametersDifferentName,
-
returnsObjectThreeParametersOnSubClass));
-
}
-
-
/**
-
* Util method to get a method, ignoring checked exceptions
-
*
-
* @param clazz
-
* @param name
-
* @param parameterTypes
-
* @return method
-
*/
-
Method method = null;
-
try {
-
method = clazz.getMethod(name, parameterTypes);
-
e.printStackTrace();
-
}
-
return method;
-
}
-
-
}
And finally, test fixtures:
-
package com.robsanheim.sandbox.reflection.overloading;
-
-
public class ConcreteClass implements Interface {
-
-
/** (non-Javadoc)
-
* implements the method in the interface type with a covariant return type
-
* @see com.robsanheim.sandbox.reflection.overloading.Interface#method()
-
*/
-
return null;
-
}
-
-
/**
-
* Overloads method in this concrete class, does not overload method from interface
-
* @param one
-
* @return
-
*/
-
return null;
-
}
-
-
return null;
-
}
-
}
-
package com.robsanheim.sandbox.reflection.overloading;
-
-
/**
-
* @author Rob Sanheim
-
*
-
* Basic interface for testing
-
*/
-
public interface Interface {
-
}

1 Comment