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