Joe
02/03/2019, 6:38 AMit::class.memberProperties.filter { prop -> prop.name == propertyName }.first().get(it)
but getting the following compiler error:
Out-projected type 'KProperty1<out DataClass!, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'
using it::class.java.getMethod("get${propertyName.capitalize()}").invoke(it)
appears to work, but it seems like there should be a way to do this through KClass directly (and avoid having to generate the getter method name)?Marc Knaup
02/03/2019, 7:52 AMit
is of type DataClass
or any of its potential subclasses.
Due to that it::class
is not KClass<DataClass>
(class descriptor for DataClass
) but KClass<out DataClass>
(class descriptor for DataClass
or any of its subclasses).
it::class.memberProperties.filter { prop -> prop.name == propertyName }.first()
thus returns KProperty1<out DataClass,Any?>
(property of a DataClass
or any of its subclasses).
You cannot call get()
in that case because the compiler cannot know what class (DataClass
or one of its subclasses) has declared the property you have found (it could be of a subclass). get()
requires a value of that subclass to be passed.
Because the compiler cannot know, get(receiver: T)
resolves to get(receiver: Nothing)
which effectively makes the method uncallable.
The way you work around this depends on the context, which is impossible to tell from the code you've shared.
One way is to cast it::class
from KClass<out DataClass>
to KClass<DataClass>
which makes get()
require a receiver of type DataClass
or any subclass. As long as you use the same value it
to both, it::class
and .get(it)
, and it
is declared as it: DataClass
then this should always be safe.
(it::class as KClass<DataClass>)
.memberProperties
.first { prop -> prop.name == propertyName }
.get(it)
You can also cast the resulting KProperty1
instead:
it::class
.memberProperties
.first { prop -> prop.name == propertyName }
.let { it as KProperty1<DataClass,Any?> }
.get(it)
The compiler will issue a warning for the cast because it cannot validate it, but that's okay.DataClass
and never in any subclass (which is the case for all data class
I guess unless there's compiler magic involved), then you can also use do it like this:
DataClass::class
.memberProperties
.first { prop -> prop.name == propertyName }
.get(it)
That way you only get properties which are declared in DataClass
- not any subclass - and thus you can pass a DataClass
instance or also a subclass instance to get()
.Joe
02/04/2019, 4:56 AM