Kotlin - memberProperties should include synthetic properties declared in java super class

Viewed 106

Consider the following Java class...

public class JavaSuperClassWithInstanceMembers {
    private final int superClassReadonlyProperty = 0;
    private int superClassMutableProperty = 0;

    public int getSuperClassReadonlyProperty() {
        return superClassReadonlyProperty;
    }

    public int getSuperClassMutableProperty() {
        return superClassMutableProperty;
    }

    public void setSuperClassMutableProperty(int value) {
        superClassMutableProperty = value;
    }

    public void superClassInstanceFunction() {
    }
}

Now lets get its memberProperties...

println(JavaSuperClassWithInstanceMembers::class.memberProperties)

val test.JavaSuperClassWithInstanceMembers.superClassReadonlyProperty: kotlin.Int,

var test.JavaSuperClassWithInstanceMembers.superClassMutableProperty: kotlin.Int

Now consider the following Kotlin class. Notice that it extends the Java class (above)...

class KotlinSubClassWithInstanceMembers : JavaSuperClassWithInstanceMembers() {

    val subClassReadonlyProperty: Int
        get() = 0

    var subClassMutableProperty: Int
        get() = 0
        set(value: Int) {}

    fun subClassInstanceFunction() {}
}

Now lets get its memberProperties...

println(KotlinSubClassWithInstanceMembers::class.memberProperties)

var test.KotlinSubClassWithInstanceMembers.subClassMutableProperty: kotlin.Int,

val test.KotlinSubClassWithInstanceMembers.subClassReadonlyProperty: kotlin.Int

According to the docs:

Returns non-extension properties declared in this class and all of its superclasses.

So why does memberProperties not result in the properties from the Java class too?

1 Answers

This is definitely strange behaviour, but exploring a bit more it seems to have nothing to do with Kotlin/Java interop. In fact, it specifically only returns a collection of accessible properties in the class, so it is the fact that the Java fields are private that is excluding them.

The members function actually makes this a lot clearer saying that it returns:

All functions and properties accessible in this class, including those declared in this class and all of its superclasses.


To illustrate my point, if you make one of the properties in KotlinSubClassWithInstanceMembers private, then from a subclass KotlinSubClassWithInstanceMembers2 of KotlinSubClassWithInstanceMembers, that private property is no longer included in the collection returned from either members or memberProperties.

open class KotlinSubClassWithInstanceMembers : JavaSuperClassWithInstanceMembers() {

    private val subClassReadonlyProperty: Int
        get() = 0
}
class KotlinSubClassWithInstanceMembers2: KotlinSubClassWithInstanceMembers() {

    val subClassProperty2: Int = 0
}

Here KotlinSubClassWithInstanceMembers2::class.members does not include subClassReadonlyProperty.

Related