【问题标题】:How to deserialize types that inherit common base class - with Gson?如何使用 Gson 反序列化继承公共基类的类型?
【发布时间】:2019-01-24 11:50:42
【问题描述】:

我有以下层次结构:

回复

public class Response implements Serializable {

    @SerializedName("message")
    @Expose
    private List<Message> messages;

    public List<Message> getMessages() {
        return messages;
    }

    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }

}

留言

public class Message implements Serializable {

        @SerializedName("type")
        @Expose
        @MessageType
        private int type;

        @SerializedName("position")
        @Expose
        @MessagePosition
        private String position;

        public int getType() {
            return type;
        }

        public String getPosition() {
            return position;
        }

        public void setType(@MessageType int type) {
            this.type = type;
        }

        public void setPosition(@MessagePosition String position) {
            this.position = position;
        }

}

文本 -> 消息

public class TextMessage extends Message {

@SerializedName("text")
@Expose
private String text;

public String getText() {
    return text;
}

public void setText(String text) {
    this.text = text;
}

}

图片 -> 消息

public class ImageMessage extends Message {

    @SerializedName("attachment")
    @Expose
    private Attachment attachment;

    public Attachment getAttachment() {
        return attachment;
    }

    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }

}

尝试使用 GSon 以这种方式反序列化 Message 会(自然)导致 textattachment 字段处的空字段。 我想要一个最合适的反序列化,它会根据响应在运行时选择与大多数字段匹配的消息类型(即文本或图像)。

到目前为止,我唯一的想法是:

1 - 使用 @JsonAdapter -> 无效

2 - 创建另一个层次结构以在编译时指向类,例如:

---- Response
   |
    - TextResponse -> List<TextMessage>
   |
    - ImageResponse -> List<ImageMessage>

第二个选项并不是我真正想要的,它让我增加了类的数量,这可能会变得过于复杂而无法应用以后的维护。

有人知道解决这个问题的方法吗?有什么可以应用的框架或概念吗?

提前致谢

【问题讨论】:

    标签: java android inheritance gson deserialization


    【解决方案1】:

    也许你可以使用 Gson extras RunTimeTypeAdapterFactory。检查这个例子:

    RuntimeTypeAdapterFactory<Message> factory = RuntimeTypeAdapterFactory
        .of(Message.class, "type") // actually type is the default field to determine
                                   // the sub class so not needed to set here
                                   // but set just to point that it is used
        // assuming value 1 in field "int type" identifies TextMessage
        .registerSubtype(TextMessage.class, "1")
        // and assuming int 2 identifies ImageMessage
        .registerSubtype(ImageMessage.class, "2");
    

    然后使用GsonBuilder.registerTypeAdapterfactory(factory)来使用这个。

    这只是在 Gson 核心库中找不到。你需要fetch it here。您可能还可以从全局 repo 中找到一些 Maven/Gradle dep,但可能最简单的方法就是复制此文件。

    如果您需要修改其行为,它会启用以后的黑客攻击。

    【讨论】:

    • 出色的答案!似乎正是我想要的。尽管我现在无法实施答案,但我会接受它,因为它对预期的解决方案有意义。希望在不久的将来检查它是否真的正确,或者通过其他人的评论在这里找到。
    【解决方案2】:

    我用GodClass 实现了这个,它包含所有消息类型字段。

    但您没有在应用程序中将此 POJO 类用作 DTO(数据传输对象)。

    Json是协议,不支持Inheritance

    在同一场景中,我为 DTO 实现了这种继承和层次结构。

    PS:我的回答中的 DTO 是我们传递的模型,例如 AdapterActivity 等等。

    【讨论】:

    • 我想过让Response 一个抽象类推断一个枚举以仅定义消息类型,但这只会有助于避免递归调用强制转换TextMessageImageMessage 等。不过,不太确定这或GodClass 是否可行。到目前为止,这当然不是最好的选择。
    • 这就是你想要的! javacodegeeks.com/2012/04/… 但我认为它弄脏了我的代码。您应该以任何方式强制转换或检测应该反序列化的类型!
    • 类似的东西——在完美的世界里,会有一个注释@Deserialize(using = TextMessage.class, ImageMessage.class)。在我的情况下,铸造不会是一个真正的问题。我将尝试阅读这篇文章,谢谢=)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    相关资源
    最近更新 更多