In Scala, given a subclass, how to check if it overrides the default method of its parent interface (defined in Java) using reflection?

Viewed 167
(defined in Java)
interface Foo {
  default int bar() {
    throw new RuntimeException("not implemented");
  }
}

(defined in Scala)
class FooImpl extends Foo {
  override int bar() {
    return 42;
  }
}

In the above code snippet, I have an interface defined in Java, with a default method bar which just throws exception. The question is how to check if a subclass FooImpl overrides the default method or not. It seems in Java we can check the declaring class on the Method instance from reflection: if FooImpl overrides the method, the declaring class will be itself, and otherwise will be the interface Foo.

However above seems not true in Scala (2.12): in both situations the declaring class will be FooImpl.

2 Answers

For example if I have something like this:

interface Test {
    default void go() {

    }
}

static class Impl implements Test, AutoCloseable {

    @Override
    public void go() {

    }

    @Override
    public void close() throws Exception {

    }
}

I can find out if Method m is the one you are looking for by:

 private static boolean isDefaultAndOverridden(Method m, Class<?> cls) {

    Class<?>[] interfaces = ClassUtils.getAllInterfacesForClass(cls);
    System.out.println(Arrays.toString(interfaces));


    return Arrays.stream(interfaces)
                 .flatMap(in -> Arrays.stream(in.getDeclaredMethods()))
                 .filter(Method::isDefault)
                 .filter(method -> method.getName().equals(m.getName()))
                 .filter(method -> method.getReturnType() == m.getReturnType())
                 .filter(method -> Arrays.equals(method.getParameterTypes(), m.getParameterTypes()))
                 .count() == 1;

}    

I am using ClassUtils from Spring to get all the interfaces that a class implements, direct or not. There are many libraries that exposes such functionality also (but it's not that complicated to write it yourself)

.getDeclarignClass seems to work fine for me.

Here is what I did. In java:

interface Foo {
   default String bar() {
      return "bar";
   }
   default String baz() {
     return "baz";
   }
}

In scala:

class Bar extends Foo {
    override def bar() = "baz"
}

object Bar {
    def main(argv: Array[String]) = classOf[Bar]
      .getMethods.filter(_.getName.startsWith("ba"))
      .map { m => m.getName -> m.getDeclaringClass.getName }
      .foreach(println)
}

This prints:

(bar,Bar)
(baz,Foo)

So, something like this should work:

    def isOverridden(mtd: Method, clazz: Class) = 
       mtd.getDeclaringClass == clazz
Related