gson 反序列化json以查找MapAndroidKotlin的对象

kg7wmglp  于 2022-11-06  发布在  Android
关注(0)|答案(1)|浏览(166)

在我的应用程序中,我使用套接字。从套接字传入的消息是json,我想将每个jsonMap到每个相应的对象。
例如,我有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永远不会有相同类型的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对象。
是否有任何机制或库可以在哪个对象中找到jsonMap?

balp4ylt

balp4ylt1#

你可以用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内容应该有一些独特的区别特征,这样反序列化库才能将其Map到特定的类型。
最简单的实现方法是将带有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
    }
}

相关问题