使用 Gson & Retrofit 使用多态 json "data: put_anything_here "

Posted

技术标签:

【中文标题】使用 Gson & Retrofit 使用多态 json "data: put_anything_here "【英文标题】:Consuming polymorphic json "data: put_anything_here " with Gson & Retrofit使用 Gson & Retrofit 使用多态 json "data: put_anything_here " 【发布时间】:2021-12-30 18:09:07 【问题描述】:

我不确定多态是否是正确的术语,所以我很抱歉。

我正在使用以下 API:

请求正文


    "user_id": "user_id",
    "command": "submit_document",

回应


    "result": "success",
    "code": 200,
    "status": "ok",
    "screen": "documents_rejected", // This is unique for different `data`
    "next_screen": "",
    "message": "Successful",
    "data": 
       // `data` is always a json object with known fields and parameters
    

我已经为不同类型的data 响应准备了数据类,例如:

data class PhoneData(
        @SerializedName("phone_number")
        val phoneNumber: String? = null,
        @SerializedName("phone_status")
        val phoneStatus: String? = null
)

"screen": "phone" 和以下用于另一个屏幕:

data class Data(
        val deepLink: String? = null
)

问题是,一开始,我必须发出以下请求来检索当前屏幕:


    "user_id": "user_id",
    "command": "get_current_screen",

返回与上述类似的响应:


    "result": "success",
    "code": 200,
    "status": "ok",
    "screen": "main_screen", // Different types of screen types are known.
    "next_screen": "",
    "message": "Successful",
    "data": 
       // `data` is always a json object but the object could contain anything depending on the `screen` type.
    

但数据字段可能包含任何内容,具体取决于 screen

data class SplashScreenData(
        // How do I make this data class combine all other data classes? One ugly approach is to add all the fields from different `data` classes here and use this one only.
)

我发现了用于多态情况的 RuntimeTypeAdapterFactory,但我不确定如何在 data 对象中没有类似“类型”的字段时使其工作(screen 是唯一的,但它在数据对象之外)。

如果有人有解决方案或可以为我指明方向,那将非常有帮助。

【问题讨论】:

调用获取数据的时候你知道数据是什么类型吗?如果是这样,您可以将数据的类型设置为模板参数并以这种方式对其进行解析(您必须告诉 GSON 模板是什么)。如果您不知道但有一组固定的可能性,您可以编写一个自定义反序列化器来查看数据并正确反序列化它,但数据可能需要键入 Any。 没有。打电话的时候不知道是什么类型。是的,有一组固定的可能性。会试试的,谢谢! 您可以使用screen 参数将data 对象反序列化或序列化到其各自的类中。 不知道为什么你之前没有尝试搜索并节省你和其他人的时间,但是 Gson 几乎内置了这个:***.com/questions/19588020/… 【参考方案1】:
                val frameTextReceived: String = frame.readText()
                val jsonObject = JsonParser.parseString(frameTextReceived).asJsonObject
                val type = when (jsonObject.get("type").asString) 
                    TYPE_JOIN_ROOM -> JoinRoom::class.java
                    TYPE_GAME_MOVE -> GameMove::class.java
                    TYPE_DISCONNECT_REQUEST -> DisconnectRequest::class.java
                    else -> BaseModel::class.java
                
                val payload = gson.fromJson(frameTextReceived, type)

这是我的解决方案,这里我有 type 参数,通过它我可以知道我必须在哪个类中反序列化对象,但在你的情况下,你有 screen 参数,你可以使用它。

【讨论】:

以上是关于使用 Gson & Retrofit 使用多态 json "data: put_anything_here "的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Retrofit2,RxJava2,Gson TypeAdapterFActory正确映射Gson?

如何使用 gson/retrofit 获取对象数组?

当列表的各个项目使用Retrofit和Gson的格式不同时,如何解析json列表?

如何使用 Retrofit2 和 GSON 转换器解决“古怪”的 JSON API

android之Retrofit使用

如何使用 Gson 和 Retrofit 将类似的 Json 对象转换为 Json 数组