使用 GSON 和 Retrofit 解析嵌套的多态对象 [英] Parsing Nested Polymorphic Objects with GSON and Retrofit

查看:67
本文介绍了使用 GSON 和 Retrofit 解析嵌套的多态对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试显示具有不同类型 ViewHolder(即文本、图像文本、视频等)的消息列表.我以这种格式从 API 中获取了这些对象的列表:

I am trying to show list of messages with different types of ViewHolders i.e. Text, ImageText, Video etc. I get a list of these objects from API somewhat in this format:

{
 "message":"success",
 "total_pages":273,
 "current_page":1,
 "page_size":10,
 "notifications":[
  {
     "id":4214,
     "notification_message":"test notification 1",
     "meta_data":{
        "messageId":"19819189",
        "viewHolderType":"textOnly",
        "body":{
           "time":"10-06-21T02:31:29,573",
           "type":"notification",
           "title":"Hi, Welcome to the NT experience",
           "description":"This is the welcome message",
           "read":true
        }
     }
  },
  {
     "id":9811,
     "notification_message":"test vss notification",
     "meta_data":{
        "messageId":"2657652",
        "viewHolderType":"textWithImage",
        "body":{
           "time":"11-06-21T02:31:29,573",
           "type":"promotions",
           "title":"Your Package - Premium",
           "description":"Thank you for subscribing to the package. Your subscription entitles you to Premium 365 Days Plan (worth $76.61)",
           "headerImage":"www.someurl.com/image.jpg",
           "read":true
        }
     }
  }
 ]
}

现在我必须从客户端模块的网络模块解析这个列表,它将只使用元数据中的对象.为此,我创建了以下类:

Now I have to parse this list from network module for client module which will use only the objects inside meta_data. To that end I have created following classes:

open class BaseMessageListItem

internal data class MessageListResponse(
@field:SerializedName("current_page")
val current_page: Int,

@field:SerializedName("notifications")
val notifications: List<MessageListItem>,

@field:SerializedName("message")
val message: String,

@field:SerializedName("page_size")
val page_size: Int,

@field:SerializedName("total_page")
val total_page: Int
)

internal data class MessageListItem(
@field:SerializedName("id")
val id: String,

@field:SerializedName("notification_message")
val notification_message: String,

 @field:SerializedName("meta_data")
val meta_data: MessageListMetaDataItem,
)


internal data class MessageListMetaDataItem(
@field:SerializedName("messageId")
val messageId: String = "",

@field:SerializedName("viewHolderType")
val viewHolderType: String = "",

@field:SerializedName("body")
val body: BaseMessageListItem = BaseMessageListItem() 
)

internal data class ImageMessageListItem(
@field:SerializedName("description")
val description: String,

@field:SerializedName("headerImage")
val headerImage: String,

@field:SerializedName("read")
val read: Boolean,

@field:SerializedName("time")
val time: String,

@field:SerializedName("title")
val title: String,

@field:SerializedName("type")
val type: String
): BaseMessageListItem()

internal data class TextMessageListItem(
@field:SerializedName("description")
val description: String,

@field:SerializedName("read")
val read: Boolean,

@field:SerializedName("time")
val time: String,

@field:SerializedName("title")
val title: String,

@field:SerializedName("type")
val type: String
): BaseMessageListItem()

通知>元数据>主体可以是多态的.我有一组扩展到 BaseMessageListItem 的类(用于 ImageItem、ImageWithTextItem、VideoItem 等).

The notifications>meta_data>body can be polymorphic. I have set of classes (for ImageItem, ImageWithTextItem, VideoItem etc) which extend to BaseMessageListItem.

private var runtimeTypeAdapterFactory: RuntimeTypeAdapterFactory<BaseMessageListItem> = RuntimeTypeAdapterFactory
    .of(BaseMessageListItem::class.java, "viewHolderType")
    .registerSubtype(ImageMessageListItem::class.java, MessageListItemTypes.TEXT_WITH_IMAGE.value)
    .registerSubtype(TextMessageListItem::class.java, MessageListItemTypes.TEXT_ONLY.value)

private var gson: Gson = GsonBuilder()
    .registerTypeAdapterFactory(runtimeTypeAdapterFactory)
    .create()

我尝试在 RuntimeTypeAdapterFactory 中使用 viewHolderType 解析它,但由于它不是 BaseMessageListItem 的属性,因此无法解析它.

I tried parsing it using viewHolderType in RuntimeTypeAdapterFactory but since it's not a property of BaseMessageListItem, it is not able to parse it.

任何人都有处理这种类型的 JSON 的经验,请分享任何指针.

Any one has any experience dealing with this type of JSON, please do share any pointers.

推荐答案

RuntimeTypeAdapterFactory 需要将 viewHolderType 字段直接放入 body对象.为了解决这个问题,你有要么修补 RuntimeTypeAdapterFactory(它甚至不作为编译的 JAR 发布,而是作为源代码自由修改仍保留在公共存储库中),或者修复您的类层次结构以提升缺失的字段,因为它只能处理同一嵌套级别的字段.

RuntimeTypeAdapterFactory requires the viewHolderType field to be put right into the body objects. In order to fix this, you have either patch RuntimeTypeAdapterFactory (it is not even published as a compiled JAR, but rather still retains in the public repository as source code free to modify), or fix your class hierarchy to lift up the missing field because it can only work with fields on the same nest level.

internal var gson: Gson = GsonBuilder()
        .registerTypeAdapterFactory(
                RuntimeTypeAdapterFactory.of(BaseMessageListMetaDataItem::class.java, "viewHolderType")
                        .registerSubtype(TextWithImageMessageListMetaDataItem::class.java, "textWithImage")
                        .registerSubtype(TextOnlyMessageListMetaDataItem::class.java, "textOnly")
        )
        .create()

internal data class MessageListItem(
        @field:SerializedName("meta_data")
        val metaData: BaseMessageListMetaDataItem<*>?,
)

internal abstract class BaseMessageListMetaDataItem<out T>(
        @field:SerializedName("viewHolderType")
        val viewHolderType: String?,
        @field:SerializedName("body")
        val body: T?
) where T : BaseMessageListMetaDataItem.Body {

    internal abstract class Body

}

internal class TextOnlyMessageListMetaDataItem
    : BaseMessageListMetaDataItem<TextOnlyMessageListMetaDataItem.Body>(null, null) {

    internal data class Body(
            @field:SerializedName("title")
            val title: String?
    ) : BaseMessageListMetaDataItem.Body()

}

internal class TextWithImageMessageListMetaDataItem
    : BaseMessageListMetaDataItem<TextWithImageMessageListMetaDataItem.Body>(null, null) {

    internal data class Body(
            @field:SerializedName("title")
            val title: String?,
            @field:SerializedName("headerImage")
            val headerImage: String?
    ) : BaseMessageListMetaDataItem.Body()

}

这篇关于使用 GSON 和 Retrofit 解析嵌套的多态对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆