Sunday, January 16, 2005

Wrong method with reflection

Try this:

public Method getUnaryMethod(final Class clazz,
        final String name, final Class parameterType)
        throws NoSuchMethodException {
    return clazz.getMethod(name, parameterType);

Looks easy, doesn't it? But:

private static class Overloaded {
    public Class foo(final Number number) { return number.getClass(); }
    // public Class foo(final Integer integer) { return integer.getClass(); }

void void testGetUnaryMethod() throws Exception {
    final Class expected = Integer.class;
    final Class actual = getUnaryMethod(Overloaded.class,
            "foo", expected).getParameterTypes()[0];

    assertEquals(expected, actual);

The test throws! To pass the test, uncomment the second definition of foo. Unfortunately, I'm working on a dispatch system and this sort of thing is death. Why? Because I cannot repeat with reflection this simple call:

new Overloaded().foo(new Integer(3));

There is a solution, though, replace getMethod with:

public static Method getMethod(final Class clazz,
        final String name, final Class parameterType)
        throws NoSuchMethodException {
    for (Class c = parameterType; null != c; c = c.getSuperclass())
        try {
            return clazz.getMethod(name, c);

        } catch (final NoSuchMethodException e) { }

    return clazz.getMethod(name, parameterType);

I look up the inheritance tree for parameterType until I find the first exact match via reflection and return that method. The catch block just lets me retry the lookup one branch higher in the tree. If I exhaust the tree, there is no match even with inheritance, in which case I retry the original lookup so as to throw the same exception as Class.getMethod(String, Class[]) would.

Now I can dispatch dynamically with reflection the same as would the Java runtime. The only drawback is that this simple algorithm only works to vary a single parameter type. For true multiple dispatch, I need a better algorithm to vary more than one parameter type and detect ambiguities: this would let me work methods with more than one argument.

Post a Comment