Ktor自定义json对象反序列化

Posted

技术标签:

【中文标题】Ktor自定义json对象反序列化【英文标题】:Ktor custom json object deserialization 【发布时间】:2021-06-24 17:31:24 【问题描述】:

我是 Ktor 的新手,我来自 Retrofit 背景,我想映射这个 json:


  "key1": "value1",
  "key2": "value2",
  ...

into(其实我不需要把json本身映射成反序列化的版本):

[
  "key1": "value1",
  "key2": "value2",
  ...
]

@Serializable
data class MyObject(
    val member1: String,
    val member2: String
)

我在官方文档中看到的示例并没有太大帮助,所以我尝试了类似的方法:

@InternalSerializationApi
object CustomDeserializer : DeserializationStrategy<List<MyObject>> 

    @ExperimentalSerializationApi
    override val descriptor = buildSerialDescriptor("MyObject", PolymorphicKind.OPEN)
        element("key", String.serializer().descriptor)
        element("value", String.serializer().descriptor)
    

    @ExperimentalSerializationApi
    override fun deserialize(decoder: Decoder): List<MyObject> = decoder.decodeStructure(descriptor) 
        val result = ArrayList<MyObject>()
        loop@ while (true) 
            val index = decodeElementIndex(descriptor)
            if (index == DECODE_DONE) 
                break@loop
             else if (index > 1) 
                throw SerializationException("Unexpected index $index")
             else 
                result.add(MyObject(decodeStringElement(descriptor, index = 0), decodeStringElement(descriptor, index = 1)))
            
        
        return result
    

问题:

    我是在正确的道路上,还是有更好的方法来实现它? 如何将此添加到我的客户? (可能只针对特定请求)

ps:这就是我使用 Gson 的方式(忽略它在 Java 中的事实):

public class MyObjectConverterFactory implements JsonDeserializer<List<MyObject>> 

    @Override
    public List<MyObject> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException 
        List<MyObject> res = new ArrayList<>();
        if (json != null && json.getAsJsonObject() != null) 
            JsonObject object = json.getAsJsonObject();
            Set<String> keys = object.keySet();
            for (String key : keys) 
                res.add(new MyObject(key, object.get(key).getAsString()));
            
        
        return res;
    

【问题讨论】:

您使用的是kotlinx.serialization,对吗?为什么插件生成的序列化程序不适合?如果原因是class和json中的字段名不匹配,可以用@SerialName注解修复:@Serializable data class MyObject(@SerialName("key1") val member1: String, @SerialName("key2") val member2: String) 是的,我正在使用,但问题是我想要一个 List 但 API 返回一个带有 MyObject、MyObject、MyObject 的巨大 json 对象......但它是一个 json 对象而不是json 数组。我想创建一个自定义反序列化器来捕获它并以所需的格式返回数据。 【参考方案1】:

据我从 GSON 实现中获得,您需要从 JSON 反序列化

"key1":"value1","key2":"value2", ...

进入

listOf(MyObject(member1="key1", member2="value1"), MyObject(member1="key2", member2="value2"), ...)

kotlinx.serialization 也可以:

object MyObjectListSerializer : JsonTransformingSerializer<List<MyObject>>(ListSerializer(MyObject.serializer())) 
    override fun transformDeserialize(element: JsonElement) =
        JsonArray((element as JsonObject).entries.map  (k, v) ->
            buildJsonObject 
                put("member1", k)
                put("member2", v)
            
        )


用法(普通的kotlinx.serialization):

val result = Json.decodeFromString(MyObjectListSerializer, "\"key1\":\"value1\",\"key2\":\"value2\"")

使用(与 Ktor 客户端):

val client = HttpClient 
    install(JsonFeature) 
        serializer = KotlinxSerializer(Json 
            serializersModule = SerializersModule  contextual(MyObjectListSerializer) 
        )
    


val result = client.get<List<MyObject>>("http://localhost:8000/myObj")

【讨论】:

谢谢!只缺少一件事,我如何将这个 MyObjectListSerializer 添加到 ktor 客户端? 更新了我的答案

以上是关于Ktor自定义json对象反序列化的主要内容,如果未能解决你的问题,请参考以下文章

Qt中 使用Json 对自定义对象进行序列与反序列化 之二

Qt中 使用Json 对自定义对象进行序列与反序列化 之一

C#中使用Newtonsoft.Json序列化和反序列化自定义类对象

使用 Json.NET 自定义反序列化

c# 通过json.net中的JsonConverter进行自定义序列化与反序列化

如何将多个键值条目的 JSON 对象反序列化为 Rust 中的自定义结构