#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
что функции не могут быть не окончательными.
Возможные обходные пути:
- Определите
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
- Вручную передать сериализатор для
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. Спасибо за предложение. Я знаю, что я вызываю напрямую, это сработало бы. Когда я найду время, я попробую ваши предложения