Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

449
Vistas
Implementando un método genérico en la interfaz que usa la clase de implementadores

Quiero un método en una interfaz principal/clase abstracta que haga uso de métodos genéricos para pasar la clase de la clase de implementación.

 interface Domain { fun toJSON(): String { return Json.encodeToString(this) } } @Serializable class User: Domain { val a: Int }

Esto no funciona ya que Json.encodeToString no conoce la clase de 'esto'.

@Serializable parece implementar KSerializer , por lo que, en teoría, podría requerir que el dominio descienda de él, pero esa interfaz tiene una plantilla. Y marcar la clase de implementación @Serializable no parece implementar KSerializer hasta el momento de la compilación, por lo que crea errores.

¿Cómo implemento este toJSON() o le digo a Domain que sus implementadores deben ser @ KSerializer @Serializable

También he probado:

 interface Domain<T> { fun toJSON(): String { return Json.encodeToString(this) } } @Serializable class User: Domain<User> { val a: Int }

Pero esto resulta en:

kotlin.IllegalStateException: Only KClass supported as classifier, got T

Una complicación adicional en todo esto es que estoy intentando hacer esto en KMM.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

No funciona, porque encodeToString() resuelve el tipo en tiempo de compilación, no en tiempo de ejecución (usa tipo cosificado).

Tal vez haya una mejor manera, pero puede hacerlo adquiriendo un serializador manualmente, resolviendo el tipo en tiempo de ejecución:

 fun toJSON(): String { val serializer = Json.serializersModule.serializer(this::class.createType()) return Json.encodeToString(serializer, this) }

Tenga en cuenta que esto solo funcionará en JVM. Si necesita hacer esto en KMM, tenga en cuenta que la reflexión multiplataforma es complicada y/o necesita algo de tiempo para madurar. kotlinx.serialization proporciona una manera de hacer esto, pero hay advertencias sobre posibles comportamientos incoherentes entre plataformas:

 @OptIn(InternalSerializationApi::class) fun toJSON(): String { @Suppress("UNCHECKED_CAST") val serializer = this::class.serializer() as KSerializer<Any?> return Json.encodeToString(serializer, this) }
over 4 years ago · Santiago Trujillo Denunciar

0

Json.encodeToString usa un genérico cosificado para acceder a la clase del parámetro. Significa que usa el tipo declarado del parámetro (conocido en tiempo de compilación), que aquí es Domain .

El enfoque más simple sería simplemente usar su propia función de extensión cosificada genérica para capturar la clase declarada del receptor con mayor precisión:

 interface Domain inline fun <reified T : Domain> T.toJSON(): String = Json.encodeToString(this) @Serializable data class User( val name: String, val age: Int, ): Domain fun main() { val user = User("Bob", 35) println(user.toJSON()) }

Tenga en cuenta, sin embargo, que esto adolece del mismo problema: si intenta usar esta extensión en una variable declarada con el tipo Domain , aún no intentará acceder al tipo de tiempo de ejecución:

 val user: Domain = User("Bob", 35) println(user.toJSON()) // still a problem here

Si realmente desea usar el tipo dinámico, puede acceder al serializador dinámicamente como @broot mencionado en su respuesta .

over 4 years ago · Santiago Trujillo Denunciar

0

@Serializable parece implementar KSerializer

Eso no es cierto. @Serializable es una anotación que indica al procesador de anotaciones que genere (entre otras cosas) un método serializer() (para el objeto complementario), que devuelve una instancia de KSerializer para esta clase. No agrega nuevas interfaces para la clase en sí, por lo que no puede decirle al sistema de tipos qué debe verificar.

Si no se encuentra un serializador, obtendrá un error de tiempo de ejecución:

 import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json class HasNoSerializableAnnotation fun main() { // Compiles fine, but will throw runtime exception // kotlinx.serialization.SerializationException: Serializer for class 'HasNoSerializableAnnotation' is not found. Json.encodeToString(HasNoSerializableAnnotation()) }

Eso es intencional porque es posible serializar instancias de clases sin un serializador generado por un complemento (incluso si no pasa el serializador personalizado manualmente al método encodeToXXX como otro parámetro, pasando el serializador (como contextual) en serializersModule ).

¿Cómo implemento este método toJSON() o le digo a Domain que sus implementadores deben ser @Serializable?

No hay manera de hacer esto. Puede tener esta API, pero es propensa a errores de tiempo de ejecución:

 interface Domain inline fun <reified T : Domain> T.toJSON() = Json.encodeToString(this)

¿Cómo implemento este método toJSON() o le digo a Domain que sus implementadores deben ser KSerializer?

En realidad, no necesita KSerializer completo aquí, solo su parte de serialización:

 interface Domain inline fun <reified T : Domain> T.toJSON(serializer: SerializationStrategy<T>) = Json.encodeToString(serializer,this)
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda