Kotlin Serialization 快速构建JsonObject & 泛型反序列化

851 阅读1分钟

基本使用

kotlinlang.org/docs/serial…

构建json对象代码为何如此繁琐?

比如构建如下json:

{ 
  "cpu": 10,
  "memory": {
     "total": 2048,
     "usage": 800
  },
  "loadingTime": 15
}

使用JsonObject构造函数

val jsonObject = JsonObject(
    mapOf(
        "cpu" to JsonPrimitive(10),
        "memory" to JsonObject(
            mapOf(
                "total" to JsonPrimitive(2048),
                "usage" to JsonPrimitive(800),
            ),
        ),
        "loadingTime" to JsonPrimitive(15),
    ),
)

使用buildJsonObject

val jsonObject = buildJsonObject {  
    put("cpu", JsonPrimitive(10))  
    put("memory",  
        buildJsonObject {  
            put("total", JsonPrimitive(2048))  
            put("usage", JsonPrimitive(800))  
        },  
    )  
    put("loadingTime", JsonPrimitive(15))  
},

由于JsonObject严格限制了value的类型,导致我们的构建代码过于啰嗦。

再来欣赏下mapOf的版本:

val map = mapOf(
   "cpu" to 10,
   "memory" to mapOf(
       "total" to 2048,
       "usage" to 800,
   ),
   "loadingTime" to 15,
)

明显mapOf更加简洁,几乎接近原始的json

如何支持媲美mapOf的语法?

fun jsonOf(vararg pairs: Pair<String, Any?> = emptyArray()): JsonElement {
    return mapOf(*pairs).toJsonElement()
}

private fun Any?.toJsonElement(): JsonElement = when (this) {
    null -> JsonNull
    is JsonElement -> this
    is Number -> JsonPrimitive(this)
    is Boolean -> JsonPrimitive(this)
    is String -> JsonPrimitive(this)
    is Array<*> -> JsonArray(map { it.toJsonElement() })
    is List<*> -> JsonArray(map { it.toJsonElement() })
    is Map<*, *> -> JsonObject(map { it.key.toString() to it.value.toJsonElement() }.toMap())
    else -> Json.encodeToJsonElement(serializer(this::class.createType()), this)
}

构建上述json的代码如下:

val json = jsonOf(
    "cpu" to 10,
    "memory" to jsonOf(
        "total" to 2048,
        "usage" to 800,
    ),
    "loadingTime" to 15,
)

其中this::class.createType()这里使用到了反射,需要引入implementation(kotlin("reflect")) 参考:kotlinlang.org/docs/reflec…

反序列化泛型支持

val data: T = Json.decodeFromJsonElement(serializer(T::class.createType()), json)

如果<T>不能声明为reified, 可以通过反射拿到对应的KType