dimanche 23 avril 2017

Generics on KProperty1.getDelegate too restrictive?

I am trying to obtain all property delegates of a certain type in a class hierarchy. This is presenting me with some issues. For a start, there seems to be no straightforward way to obtain a class' superclass in Kotlin. The first way I tried was to use Java's Class.getSuperclass:

private fun <T : Any> KClass<T>.getSuperclass(): KClass<in T>? = (java.superclass as? Class<out Any>)?.kotlin as KClass<in T>

But this requires an unchecked cast, because Kotlin will not allow me to convert a Class<in T> back to Kotlin, because apparently in T means it could be something that is not Any, whatever that might be ("Type parameter has an upper bound 'Any' that cannot be satisfied capturing 'in' projection").

So I tried a pure Kotlin solution: First get all superclasses including interfaces (KClass.superclasses) and then filter out every interface. But there is nothing on KClass that tells me if it's an interface! So I have to go to Java for that again. And it again requires an unchecked cast, because for some reason KClass.superclasses is of type List<KClass<*>> and not List<KClass<in T>>:

private fun <T : Any> KClass<T>.getSuperclass123(): KClass<in T>? = superclasses.firstOrNull { it.java.isInterface } as KClass<in T>?

Am I missing something here? I must be.

Now for the actual question, trying to obtain all property delegate instances in a class hierarchy. First I wrote a function to obtain the instances for one class:

private fun <T : Any> KClass<T>.getProperties(obj: T) =
    declaredMemberProperties.also { it.forEach { it.isAccessible = true } }.asSequence().filter { it.getDelegate(obj) is MyPropertyDelegate }

Works fine. But of course I also need all the properties declared in superclasses. So naturally I tried to change the receiver to KClass<in T> which of course results in me not being able to call declaredMemberProperties anymore. How do I solve this?

I already tried using KClass.memberProperties, but it falls short if a subclass overrides a property which is delegated in a parent class. In that case it will only list the overridden property, which does not allow me to access the property delegate instance.





Aucun commentaire:

Enregistrer un commentaire