Weird behavior of getting property by reflection

for the following code ,the get() method show an error

Out-projected type ‘KProperty1<out Foo, Any?>’ prohibits the use of ‘public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1’



class Foo(){
    val a = 1
}

fun test(){
    val foo = Foo()
    foo::class.memberProperties.find { it.name == "a" }.let{
        it.get(foo)
    }
}

and the IDE show that get() expect a Nothing

how can I get or set the property

my environment

// kotlin
    implementation 'androidx.core:core-ktx:1.1.0-alpha05'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.30"
    implementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.30'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
1 Like

See explanation here.

Possible workarounds:

Foo::class.memberProperties.find { it.name == "a" }?.get(foo)
(foo::class as KClass<Foo>).memberProperties.find { it.name == "a" }?.get(foo)
3 Likes

I had a similar problem, but for a more generic requirement. As this is a top Google hit for this error message, I thought I’d share my situation.

I’m trying to find the name of all non-null properties on any type of object.

I had this:

val nonNullPropertyNames = obj::class.memberProperties
    .filterNot { it.get(obj) == null }.map { it.name }

but was getting this error on the get call:

Out-projected type 'KProperty1<out Any, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'

Inspired by @Alexey.Belkov’s suggestions above, I tried casting the class at the start of the expression:

val nonNullPropertyNames = (obj::class as KClass<Any>).memberProperties
    .filterNot { it.get(obj) == null }.map { it.name }

And now it works!

I get a warning about Unchecked cast: KClass<out Any> to KClass<Any>, however in this situation I know it is safe because the obj I pass into get() is the same as the one that I got the KClass from. If that weren’t the case (i.e. you can’t guarantee that the property came from the exact same KClass as the object you’re passing in), then making this cast could cause runtime errors as you might call get() with an object that doesn’t actually have the property.

1 Like

Another observation:

If you’re using this::class you will get this as well. In case you know what this is (i. e. a class where you’re currently writing a regular function in) you can just specify the class name explicitly: Foo::class. That gives the compiler the necessary hint.