To find properties that delegate to a delegate class along with the instance of that class, here is a utility function:
data class DelegatedProperty<T : Any, DELEGATE : Any>(val property: KProperty1<T, *>, val delegatingToInstance: DELEGATE)
inline fun <reified T : Any, DELEGATE : Any> findDelegatingPropertyInstances(instance: T, delegatingTo: KClass<DELEGATE>): List<DelegatedProperty<T, DELEGATE>> {
return T::class.declaredMemberProperties.map { prop ->
val javaField = prop.javaField
if (javaField != null && delegatingTo.java.isAssignableFrom(javaField.type)) {
javaField.isAccessible = true // is private, have to open that up
@Suppress("UNCHECKED_CAST")
val delegateInstance = javaField.get(instance) as DELEGATE
DelegatedProperty(prop, delegateInstance)
} else {
null
}
}.filterNotNull()
}
A few notes:
- First correct your reified type
T
to T: Any
or you cannot access all of the extensions in Kotlin reflection including declaredMemberProperties
- It is easiest to get to the field from a property reference to be sure you are actually talking about something that is really a property, so for each of
declaredMemberProperties
use javaField
to do so.
- Since
javaField
is a custom getter and could be nullable, it is saved to a local variable so smart casting will work later.
- Then if this field has the same type as the delegation class you are looking for, you can then access the field.
- But first you have to force the field's accessibility because it is a
private
field.
Running this in test program:
class DelegationExample {
operator fun getValue(ref: Any, prop: KProperty<*>) = 0
}
class Example {
val a by DelegationExample()
val b by DelegationExample()
val c by DelegationExample()
}
fun main(args: Array<String>) {
findDelegatingPropertyInstances(Example(), DelegationExample::class).forEach {
println("property '${it.property.name}' delegates to instance of [${it.delegatingToInstance}]")
}
}
The output is something like:
property 'a' delegates to instance of [DelegationExample@2c1b194a]
property 'b' delegates to instance of [DelegationExample@4dbb42b7]
property 'c' delegates to instance of [DelegationExample@66f57048]
KProperty0
,KProperty1
, andKProperty2
have agetDelegate
function. Does that not work? Why are the answers here using reflection when a simple built-in method exists? – Bandanna