Dada una clase de dominio con un constructor sin parámetros, ¿cómo obtenemos una referencia a ese constructor a través de la API de Reflection?
Considere, por ejemplo, una clase de datos de Student , como:
data class Student(var nr: Int = 0, var name: String? = null) Aviso, podemos confirmar la presencia del constructor sin parámetros a través de javap que muestra:
public pt.isel.Student(int, java.lang.String); descriptor: (ILjava/lang/String;)V public pt.isel.Student(int, java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker); descriptor: (ILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public pt.isel.Student(); descriptor: ()VSin embargo, ninguno de los siguientes enfoques devuelve el constructor sin parámetros:
primaryConstructor : val constructor = Student::class.primaryConstructor // java.util.NoSuchElementException: Collection contains no element matching the predicate val constructor = Student::class.constructors.first { it.parameters.isEmpty() }Alternativamente, podemos proceder a través de Java Reflection que funciona bien, pero no debería ser necesario tal desvío:
val constructor = Student::class.java.getDeclaredConstructor() Segundo, ¿por qué necesitamos eso? Porque queremos instanciar una clase de dominio en tiempo de ejecución. Sí, sabemos que createInstance() de KClass hace ese trabajo. Pero arroja IllegalArgumentException: Class should have a single no-arg constructor si no hay un constructor sin parámetros.
Por lo tanto, nos gustaría comprobar de antemano si podemos llamar a createInstance() sin excepciones.
El constructor sin parámetros aquí solo existe en la clase Java compilada, y no en su código Kotlin. En lo que respecta al código de Kotlin, su clase Student tiene un solo constructor, con 2 parámetros opcionales.
La API de reflexión de Kotlin está diseñada para ser independiente de la plataforma, por lo que debe usar la reflexión de Java para obtener el constructor de parámetros.
Si solo desea ver si puede llamar a createInstance de manera segura, puede verificar si la clase tiene un solo constructor cuyos parámetros son todos opcionales. Esto está documentado :
Crea una nueva instancia de la clase, llamando a un constructor que no tiene parámetros o todos los parámetros son opcionales. Si no hay o hay muchos constructores de este tipo, se lanza una excepción.
val isSafe = someClass.constructors.singleOrNull { it.parameters.all(KParameter::isOptional) } != null Esto es similar a cómo se implementa createInstance para lanzar la excepción.