Java – Reflection on interface overridden methods

genericsjavaoverridingreflection

I have the following code, with a generic ITest interface extended by a not generic ITestDouble interface. The op method is overridden by ITestDouble.

When I try to list all the methods of ITestDouble, I get op twice. How can I verify that they are actually the same method?

public class Test {

    public static void main(String[] args) throws NoSuchMethodException {
        for (Method m : ITestDouble.class.getMethods()) {
            System.out.println(m.getDeclaringClass() + ": " + m + "(bridge: " + m.isBridge() + ")");
        }
    }

    public interface ITestDouble extends ITest<Double> {
        @Override
        public int op(Double value);

        @Override
        public void other();
    }

    public interface ITest<T extends Number> {
        public int op(T value);

        public void other();
    }
}

Output:

interface Test$ITestDouble: public abstract int Test$ITestDouble.op(java.lang.Double)(bridge: false)
interface Test$ITestDouble: public abstract void Test$ITestDouble.other()(bridge: false)
interface Test$ITest: public abstract int Test$ITest.op(java.lang.Number)(bridge: false)

PS I know this is the same question as Java Class.getMethods() behavior on overridden methods, but that question got no real answer: the isBridge() call always returns false.

EDIT:
I'm also fine with any library which would do the dirty job of filtering out the "duplicate" op method for me.

Best Answer

Unfortunately you cannot have that information, because as far as the JVM is concerned, ITestDouble has a legitimate method op(Number) which can be totally independent of op(Double). It is actually your Java compiler that makes sure the methods always coincide.

That implies that you can create pathological implementations of ITestDouble with totally different implementations for op(Number) and op(Double) by using a pre-JDK5 compiler, or a dynamic proxy:

public static void main(String[] args) throws NoSuchMethodException {

    final Method opNumber = ITest.class.getMethod("op", Number.class);
    final Method opDouble = ITestDouble.class.getMethod("op", Double.class);
    final Method other = ITestDouble.class.getMethod("other");

    ITestDouble dynamic = (ITestDouble) Proxy.newProxyInstance(
            ITestDouble.class.getClassLoader(),
            new Class<?>[]{ITestDouble.class},
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
                    if (opDouble.equals(m)) return 1;
                    if (opNumber.equals(m)) return 2;
                    // etc....

                    return null;
                }
            });

    System.out.println("op(Double): " + dynamic.op(null);            // prints 1.
    System.out.println("op(Number): " + ((ITest) dynamic).op(null);  // prints 2. Compiler gives warning for raw types
}

EDIT: Just learned of Java ClassMate. It is a library that can correctly resolve all type variables in a declaration. It is very easy to use:

    TypeResolver typeResolver = new TypeResolver();
    MemberResolver memberResolver = new MemberResolver(typeResolver);

    ResolvedType type = typeResolver.resolve(ITestDouble.class);
    ResolvedTypeWithMembers members = memberResolver.resolve(type, null, null);
    ResolvedMethod[] methods = members.getMemberMethods();

Now if you iterate over methods you'll see the following:

void other();
int op(java.lang.Double);
int op(java.lang.Double);

Now it is easy to filter for duplicates:

public boolean canOverride(ResolvedMethod m1, ResolvedMethod m2) {
    if (!m1.getName().equals(m2.getName())) return false;

    int count = m1.getArgumentCount();
    if (count != m2.getArgumentCount()) return false;

    for (int i = 0; i < count; i++) {
        if (!m1.getArgumentType(i).equals(m2.getArgumentType(i))) return false;
    }

    return true;
}