反序列化 json 以查找哪个对象映射 Android Kotlin

Deserialize a json to find which object maps Android Kotlin

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

例如我有 json

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

匹配数据class

data class Error(
    val er: Er
)

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

但我也有一个json喜欢

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

这是数据class

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

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

所以我尝试做类似

的事情
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 映射到哪个对象?

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

interface AuthOrError

可能是反序列化结果的所有类型都应该实现它;并且所有涉及反序列化的classes都应该标上@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
    }
}