1

我有一个简单的 json,但包含字段有动态对象。例如,json 看起来像

{
    "fixedField1": "value1",
    "dynamicField1": {
        "f1": "abc",
        "f2": 123
    }
}

或者

{
    "fixedField1": "value2",
    "dynamicField1": {
        "g1": "abc",
        "g2": { "h1": "valueh1"}
    }
}

我正在尝试序列化此对象,但不确定如何映射动态字段

@Serializable
data class Response(
  @SerialName("fixedField1")
  val fixedField: String,

  @SerialName("dynamicField1")
  val dynamicField: Map<String, Any> // ???? what should be the type?
)

上面的代码失败并出现以下错误

后端内部错误:代码生成期间出现异常原因:后端(JVM)内部错误:未找到任何类型元素的序列化程序。

4

1 回答 1

3

当我不得不序列化任意时遇到了类似的问题Map<String, Any?>

到目前为止,我设法做到这一点的唯一方法是使用JsonObject/ JsonElementAPI 并将其与@ImplicitReflectionSerializer

主要的缺点是使用反射,它只能在 JVM 中正常工作,对于 kotlin-multiplatform 来说不是一个好的解决方案。

    @ImplicitReflectionSerializer
    fun Map<*, *>.toJsonObject(): JsonObject = JsonObject(map {
        it.key.toString() to it.value.toJsonElement()
    }.toMap())

    @ImplicitReflectionSerializer
    fun Any?.toJsonElement(): JsonElement = when (this) {
        null -> JsonNull
        is Number -> JsonPrimitive(this)
        is String -> JsonPrimitive(this)
        is Boolean -> JsonPrimitive(this)
        is Map<*, *> -> this.toJsonObject()
        is Iterable<*> -> JsonArray(this.map { it.toJsonElement() })
        is Array<*> -> JsonArray(this.map { it.toJsonElement() })
        else -> {
            //supporting classes that declare serializers
            val jsonParser = Json(JsonConfiguration.Stable)
            val serializer = jsonParser.context.getContextualOrDefault(this)
            jsonParser.toJson(serializer, this)
        }
    }

然后,要序列化,您将使用:


val response = mapOf(
    "fixedField1" to "value1",
    "dynamicField1" to mapOf (
        "f1" to "abc",
        "f2" to 123
    )
)


val serialized = Json.stringify(JsonObjectSerializer, response.toJsonObject())

笔记

这种基于反射的序列化仅在您被限制使用时才需要Map<String, Any?>

如果您可以自由地使用自己的 DSL 来构建响应,那么您可以json直接使用 DSL,这非常类似于mapOf

val response1 = json {
    "fixedField1" to "value1",
    "dynamicField1" to json (
        "f1" to "abc",
        "f2" to 123
    )
}

val serialized1 = Json.stringify(JsonObjectSerializer, response1)

val response 2 = json {
    "fixedField1" to "value2",
    "dynamicField1" to json {
        "g1" to "abc",
        "g2" to json { "h1" to "valueh1"}
    }
}

val serialized2 = Json.stringify(JsonObjectSerializer, response2)

但是,如果您受限于定义数据类型并进行序列化和反序列化,您可能无法使用jsonDSL,因此您必须@Serializer使用上述方法定义 a。

在 Apache 2 许可下,此类序列化程序的示例如下:ArbitraryMapSerializer.kt

Map然后您可以在具有任意s 的类上使用它。在您的示例中,它将是:

@Serializable
data class Response(
  @SerialName("fixedField1")
  val fixedField: String,

  @SerialName("dynamicField1")
  @Serializable(with = ArbitraryMapSerializer::class)
  val dynamicField: Map<String, Any>
)
于 2019-08-20T13:22:39.757 回答