Десериализация универсального объекта с помощью сериализации Kotlin

#kotlin #generics #serialization #json-deserialization

#kotlin #универсальные объекты #сериализация #json-десериализация

Вопрос:

Я пытаюсь заменить библиотеку Gson сериализацией kotlin для обработки сериализации / десериализации JSON.

Я сталкиваюсь с некоторыми проблемами при десериализации универсальных объектов. Я установил простой пример того, чего я пытаюсь достичь:

 @Serializable
data class ContentMessageDto<T>(
    val method: String,
    val content: T
)

@Serializable
private data class DummyObjectNonNullProperties(
    val value: Int,
    @SerialName("aaa") val someProp: String,
    val bbb: Boolean,
    val ccc: Double
)

interface MyParser {
    fun <T> parseContentMessage(
        json: String
    ): ContentMessageDto<T>
}

class MyParserImpl(private val jsonSerialization: Json) : MyParser {
    override fun <T> parseContentMessage(json: String): ContentMessageDto<T> {
        return jsonSerialization.decodeFromString<ContentMessageDto<T>>(json)
    }

}

fun main() {
    println("start processing...")
    val jsonToParse = """
                {
                    "method":"get",
                    "content":{
                        "value":345,
                        "aaa": "some string",
                        "bbb": true,
                        "ccc": 23.4
                    }
                }""".trimIndent()

    val parser:MyParser = MyParserImpl(Json)

    val result = parser.parseContentMessage<DummyObjectNonNullProperties>(jsonToParse)

    println("result -> $result")

}
  

Но когда я запускаю основной метод, я получаю следующую ошибку:

 Exception in thread "main" java.lang.IllegalStateException: Only KClass supported as classifier, got T
    at kotlinx.serialization.internal.Platform_commonKt.kclass(Platform.common.kt:102)
    at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:52)
    at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
    at kotlinx.serialization.SerializersKt__SerializersKt.builtinSerializerOrNull$SerializersKt__SerializersKt(Serializers.kt:79)
    at kotlinx.serialization.SerializersKt__SerializersKt.serializerByKTypeImpl$SerializersKt__SerializersKt(Serializers.kt:69)
    at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:54)
    at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
  

Но я не уверен, почему. Может ли кто-нибудь дать мне объяснение и, если возможно, несколько советов о том, как я могу это реализовать?

Ответ №1:

Это сработало бы, если бы вы просто сделали:

 val result = Json.decodeFromString<ContentMessageDto<DummyObjectNonNullProperties>>(jsonToParse)
  

Но при всем этом переносе информация о типе T была потеряна. Проблема в том, что вы не можете просто использовать reified generics здесь, потому inline что функции не могут быть не окончательными.

Возможные обходные пути:

  1. Определите parseContentMessage как функцию расширения, чтобы она могла иметь inline модификатор (и T могла быть reified ):
 interface MyParser {
    val jsonSerialization: Json
}

inline fun<reified T> MyParser.parseContentMessage(json: String): ContentMessageDto<T> {
    return jsonSerialization.decodeFromString(json)
}

class MyParserImpl(override val jsonSerialization: Json) : MyParser

//Usage will be the same
  
  1. Вручную передать сериализатор для T в parseContentMessage :
 interface MyParser {
    fun <T> parseContentMessage(json: String, contentSerializer: KSerializer<T>): ContentMessageDto<T>
}

class MyParserImpl(private val jsonSerialization: Json) : MyParser {
    override fun <T> parseContentMessage(json: String, contentSerializer: KSerializer<T>): ContentMessageDto<T> {
        return jsonSerialization.decodeFromString(ContentMessageDto.serializer(contentSerializer), json)
    }
}

//Usage:
val result = parser.parseContentMessage(jsonToParse, DummyObjectNonNullProperties.serializer())

  

Комментарии:

1. Спасибо за предложение. Я знаю, что я вызываю напрямую, это сработало бы. Когда я найду время, я попробую ваши предложения