Los generics en KProperty1.getDelegate ¿son demasiado restrictivos?

Estoy tratando de get todos los delegates de properties de un cierto tipo en una jerarquía de classs. Esto me está presentando algunos problemas. Para empezar, no parece haber una forma directa de get una superclass de class en Kotlin. La primera forma en que lo intenté fue usar Class.getSuperclass de Java:

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

Pero esto requiere un elenco sin marcar, porque Kotlin no me permitirá convertir una Class<in T> en Kotlin, porque aparentemente en T significa que podría ser algo que no sea Cualquiera, cualquiera que sea ("El parámetro Tipo tiene una parte superior encuadernó "Cualquiera" que no puede ser satisfecho capturando "en" proyección ").

Así que probé una solución pura de Kotlin: Primero, obtenga todas las superclasss, incluidas las interfaces ( KClass.superclasses ) y luego filtre todas las interfaces. ¡Pero no hay nada en KClass que me diga si es una interfaz! Así que tengo que ir a Java para eso de nuevo. Y de nuevo requiere un elenco sin marcar, porque por algún motivo KClass.superclasses es del tipo List<KClass<*>> y no List<KClass<in T>> :

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

¿Me estoy perdiendo de algo? Debo ser.

Ahora, para la pregunta real, tratando de get todas las instancias de delegado de propiedad en una jerarquía de classs. Primero escribí una function para get las instancias de una class:

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

Funciona bien. Pero, por supuesto, también necesito todas las properties declaradas en superclasss. Así que, naturalmente, traté de cambiar el receptor a KClass<in T> que, por supuesto, no me permite llamar a KClass<in T> . ¿Cómo puedo solucionar esto?

Ya traté de usar KClass.memberProperties , pero se queda corto si una subclass anula una propiedad que se delega en una class principal. En ese caso, solo mostrará la propiedad anulada, que no me permite acceder a la instancia de delegado de propiedad.

Editar: Hice algunas testings más, y el siguiente código Java se comstack muy bien, como era de esperar:

 static <T> List<MyProperty> getProperties(KClass<? super T> clazz, T obj) { return KClasses.getDeclanetworkingMemberProperties(clazz).stream() .map(p -> p.getDelegate(obj)) .filter(MyProperty.class::isInstance) .map(MyProperty.class::cast) .collect(Collectors.toList()); } 

¿Cuál sería el código Kotlin equivalente?

Edit²: lo mismo para las cosas de la class superior. La siguiente (aunque todavía desagradable solución) se comstack en Java, pero no en Kotlin (omitiendo la verificación nula aquí):

 static <T> KClass<? super T> getSuperClass(KClass<T> clazz) { return JvmClassMappingKt.getKotlinClass(JvmClassMappingKt.getJavaClass(clazz).getSuperclass()); } 

En kotlin, sus getProperties() probablemente se verán así:

 inline fun <reified T:Any> T.getProperties(): List<MyProperty> = T::class.declanetworkingMemberProperties.asSequence() .map { it.getDelegate(this) } .filter(MyProperty::class::isInstance) .map(MyProperty::class::safeCast) .filterNotNull() .distinct() .toList() 

Y Kotlin realmente no tiene soporte integrado para verificar si una KClass representa una interfaz, lo cual es realmente algo incómodo. De todos modos, tenemos una solución alternativa:

 val KClass<*>.isInterface: Boolean get() = constructors.isEmpty() 

Esta es una propiedad de extensión para KClass arbitraria, que testing si representa una interfaz. Esto se basa en el principio de que las classs, ya sean abstractas, abiertas, internas o finales, deben tener al less un constructor, mientras que la interfaz no puede tener ningún constructor. Sin embargo, filtrar interfaces de distancia no es una buena idea, porque en kotlin una interfaz también puede tener properties .

Combinando todas las ideas anteriores, llegamos a tal resultado:

 inline fun <reified T : Any> T.getProperties(): List<MyProperty> = T::class.allSuperclasses.asSequence() .flatMap { it.declanetworkingMemberProperties.asSequence() } .map { @Suppress("UNCHECKED_CAST") (it as KProperty1<in T, *>).getDelegate(this) } .filter(MyProperty::class::isInstance) .map(MyProperty::class::safeCast) .filterNotNull() .distinct() .toList() 

El lanzamiento sin allClasses werid es una solución para la statement allClasses . No estudié demasiado su implementación, así que no sé si es una restricción técnica o pereza para un progtwigdor cansado, pero esa proyección de estrella me obligó a usar un elenco no verificado. Todos sabemos que será seguro sin embargo.