【问题标题】:Deserialize a json to find which object maps Android Kotlin反序列化 json 以查找映射 Android Kotlin 的对象
【发布时间】:2020-10-31 11:28:06
【问题描述】:

在我的应用程序中,我使用套接字。来自套接字的收入消息是 jsons,我想将每个 json 映射到每个相应的对象。

例如我有 json

{ "er": { "i":"1001", "m":"message text" } }

与数据类匹配

data class Error(
    val er: Er
)

data class Er(
    val i: String,
    val m: String
)

但我也有类似的json

{
   "statusCode":200, "body":{ 
      "au":{
         "a": 44,
      }
    }
}

哪个是数据类

data class Authentication(
    val body: Body,
    val statusCode: Int
)
 
data class Body(
    val au: Au
)
data class Au(
    val a: Int
)

默认情况下,我知道我的 API 永远不会有相同类型的 jsons!

所以我尝试做类似的事情

try {
   val thing = Gson().fromJson(mJson, Error::class.java)
   // This json is Error type of object. Do something with it
catch(e: JsonSyntaxException) {
   // This json is not Error object. Maybe its  Authentication
   // Proceed to check another object
}

但是我注意到没有发生异常,thing 是一个带有空字段的Error 对象。

是否有任何机制或库可以找到 json 映射到哪个对象?

【问题讨论】:

  • 你能发一个示例 JSON 和相应的类吗?
  • 你可以想象任何 json 和任何类......这必须是一个通用函数
  • 您希望库自动找出以 JSON 编码的对象类型(无需在反序列化时提供所需的类型)?你怎么想象的?假设您有两个类 data class Class1(val str: String) data class Class2(val str: String){"str": "123"} 作为 JSON。它应该如何反序列化?作为Class1Class2 的实例?
  • 或者您希望它对反序列化严格,并在提供的 JSON 与指定类型不匹配时抛出异常?
  • 我已经编辑了这个问题,以防它现在更容易理解!

标签: json kotlin serialization gson


【解决方案1】:

您可以使用kotlinx.serialization 库来实现这一点。 但首先,您需要将可能的反序列化类型集缩小到多态类层次结构。 在大多数情况下,它可能是一个接口:

interface AuthOrError

所有类型,可能是反序列化的结果,都应该实现它;并且所有涉及反序列化的类都应该用@Serializable注解来标记:

@Serializable
data class Authentication(val body: Body, val statusCode: Int) : AuthOrError

@Serializable
data class Body(val au: Au)

@Serializable
data class Au(val a: Int)

@Serializable
data class Error(val er: Er) : AuthOrError

@Serializable
data class Er(val i: String, val m: String)

但是反序列化库不是灵媒。 JSON内容应该有一些独特的区别特征,以便反序列化库可以将其映射到特定的类型。

实现它的最简单方法 - 是将目标类型值的 FQN 的 type 字段添加到每个 JSON 对象(如 {"type": "Error", "er": { "i":"1001", "m":"message text" } })。之后您需要注册该字段的所有可能值(一组精确的类型,实现此接口,可能是反序列化结果):

val authOrErrorModule = SerializersModule {
    polymorphic(AuthOrError::class) {
        subclass(Authentication::class)
        subclass(Error::class)
    }
}

然后将其传递给serializersModule 属性,奇迹发生了:

when (val thing = Json{serializersModule = authOrErrorModule}.decodeFromString<AuthOrError>(mJson)) {
    is Authentication -> {
        println(thing.statusCode) //smart casted as Authentication
    }
    is Error -> {
        println(thing.er) //smart casted as Error
    }
}

如果无法修改 JSON 格式,那么您需要创建自己的反序列化器并手动定义基于 JSON 内容选择类型的算法(更准确地说,它的(反)序列化器)。例如,在这种情况下,您可能会说“如果 JSON 有 statusCode 字段,那么它必须是 Authentication,否则它是 Error”:

object AuthOrErrorSerializer : JsonContentPolymorphicSerializer<AuthOrError>(AuthOrError::class) {
    override fun selectDeserializer(element: JsonElement) = when {
        "statusCode" in element.jsonObject -> Authentication.serializer()
        else -> Error.serializer()
    }
}

然后将其作为序列化程序传递,瞧:

when (val thing = Json.decodeFromString(AuthOrErrorSerializer, mJson)) {
    is Authentication -> {
        println(thing.statusCode)// smart casted as Authentication
    }
    is Error -> {
        println(thing.er) // smart casted as Error
    }
}

【讨论】:

    猜你喜欢
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多