g

    Gilles Barbier

    1 year ago
    Hi all, following my question here https://kotlinlang.slack.com/archives/C7A1U5PTM/p1604077940258100 - the only way to know at run time if an Any object is serializable and get serializer would be:
    fun <T : Any> getSerializer(obj: T) : KSerializer<T>? {
        val companionField = obj::class.java.declaredFields.find {
            it.name == "Companion" && isStatic(it.modifiers)
        } ?: return null
    
        val companion = companionField.get(obj)
        val serializerMethod = try {
            companion::class.java.getMethod("serializer")
        } catch (e: NoSuchMethodException) {
            return null
        }
    
        if (serializerMethod.returnType.name !=  KSerializer::class.qualifiedName) {
            return null
        }
    
        @Suppress("UNCHECKED_CAST")
        return serializerMethod.invoke(companion) as KSerializer<T>
    }
    Is it the right way? It's seem a bit cumbersome to me. Why not to add an interface?
    Tomasz Krakowiak

    Tomasz Krakowiak

    1 year ago
    Better use kotlinx.serialization.SerializersKt#serializer(java.lang.reflect.Type) or SerializersModule.serializer(type: Type)
    g

    Gilles Barbier

    1 year ago
    Thx, I was not aware of that and ended up with
    fun <T : Any> getKSerializerOrNull(klass: Class<out T>) = 
        try {
            @Suppress("UNCHECKED_CAST")
            serializer(klass.kotlin.createType()) as KSerializer<T>
        } catch (e: Exception) { 
            null 
        }
    Hi, I come back, as there is actually issues with the proposed solution:
    klass.kotlin.createType()
    is not reliable in this context, for example if klass is a non-empty List<User>, it will fail.
    So it's still unclear to me how to deal with this situation (klass is a user provided java class, I do not have control on it)
    After digging, I can use
    @OptIn(ExperimentalStdlibApi::class)
    inline fun <reified T : Any> getKSerializerOrNull(klass: Class<out T>) = try {
        @Suppress("UNCHECKED_CAST")
        serializer(typeOf<T>()) as KSerializer<T>
    } catch (e: SerializationException) {
        null
    }
    but at the cost of using an experimental api
    Ok - actually this above does not work, as if klass comes from a deserialization, I've lost the type at runtime 😅 - so I guess I can only use the initial complex solution