Skip to content
Advertisement

How to check if a class has overriden a default method from an interface using Reflection in Kotlin or Java?

I have an interface with a default method, and two classes which implement this interface. One of the classes overrides the default method, and the other does not.

interface MyType {
  fun giveHello(): String = "Hello!"
}

class Polite: MyType {
  // Does not override giveHello()
}

class Rude: MyType {
  override fun giveHello(): String = "I don't like you"
}

I get access to the giveHello method using reflection like this:

val methodOfPolite = Polite::class.java.getDeclaredMethod("giveHello")
val methodOfRude = Rude::class.java.getDeclaredMethod("giveHello")

There’s one weird thing here. The polite class does not override the giveHello method, but the declaringClass of this method object still points to Polite.

So is there a way I can check whether the class actually did override the default interface method or not?

My use case looks something like this (assuming we can get the behaviour I’m asking for in a property called isOverriden):

if (methodOfPolite.isOverriden) {
  // do something
} else {
  // do something else
}

Advertisement

Answer

As described in KT-4779, currently Kotlin default functions are not implemented using actual Java/JVM default methods. The default implementation lives in a static method instead, and all classes using that default implementation just call that static method. This is done to ensure Kotlin default functions also work on the 1.6 JVM target which doesn’t have them yet.

So your code roughly compiles to this Java equivalent:

public interface MyType {
  public String giveHello();

  public static class MyTypeImpls {
     public static String giveHello() { return "Hello!" }
  }
}

public final class Polite implements MyType {
  //does not override
  public String giveHello() { return MyType.MyTypeImpls.giveHello() }
}

public final class Rude implements MyType {
  //does override
  override fun giveHello() { return "I don't like you" }
}

This is why java reflection thinks both classes override the function, ie because they actually do.

You need to use Kotlin reflection here, notably declaredMemberFunctions and memberFunctions:

fun overridesGiveHello<T: MyType>(cls: KClass<T>) =
        cls.memberFunctions.first { it.name == "giveHello" } in cls.declaredFunctions

println(overridesGiveHello(Polite::class)) //false
println(overridesGiveHello(Rude::class))  //true
Advertisement