jackson解決多態發序列化問題


在項目中經常會有多個子類繼承一個抽象類或者是實現一個接口,當我們需要對接收到的消息進行反序列化時,就會出現問題,代碼如下:

@Getter
@Setter
public abstract class MessageContent {

    private String contentType;

    /**
     * 消息內容(contentText)編碼方式。
     * 默認為utf8字符編碼,可選base64編碼。
     */
    private String contentEncoding;

}

它有多個子類,分別為:

@Getter
@Setter
public class MessageContentBack extends MessageContent {

    /**
     * contentType為"text/plain" 內容為字符串,其余的類型 內容為json對象。
     * 如果編碼式為base64,則內容為base64編碼之后的字符
     */
    private String contentText;
}

以及:

@Getter
@Setter
public class ContentTextSuggestionChipList extends MessageContent {

    private Suggestion contentText;
}

異常:

Can not construct instance of XXXX, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

下面我們來講講解決多態中反序列化問題的解決---jackson。
首先,先來看看幾個重要注解以及它們的參數:

@JsonTypeInfo

use:定義使用哪一種類型識別碼,它有下面幾個可選值:
    1、JsonTypeInfo.Id.CLASS:使用完全限定類名做識別
    2、JsonTypeInfo.Id.MINIMAL_CLASS:若基類和子類在同一包類,使用類名(忽略包名)作為識別碼
    3、JsonTypeInfo.Id.NAME:一個合乎邏輯的指定名稱
    4、JsonTypeInfo.Id.CUSTOM:自定義識別碼
    5、JsonTypeInfo.Id.NONE:不使用識別碼
include(可選):指定識別碼是如何被包含進去的,它有下面幾個可選值:
    1、JsonTypeInfo.As.PROPERTY:作為數據的兄弟屬性
    2、JsonTypeInfo.As.EXISTING_PROPERTY:作為POJO中已經存在的屬性
    3、JsonTypeInfo.As.EXTERNAL_PROPERTY:作為擴展屬性
    4、JsonTypeInfo.As.WRAPPER_OBJECT:作為一個包裝的對象
    5、JsonTypeInfo.As.WRAPPER_ARRAY:作為一個包裝的數組
property(可選):制定識別碼的屬性名稱
    此屬性只有當use為
        JsonTypeInfo.Id.CLASS(若不指定property則默認為@class)
        JsonTypeInfo.Id.MINIMAL_CLASS(若不指定property則默認為@c)
        JsonTypeInfo.Id.NAME(若不指定property默認為@type)
    include為JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY時才有效
defaultImpl(可選):如果類型識別碼不存在或者無效,可以使用該屬性來制定反序列化時使用的默認類型
visible(可選,默認為false):propery中的屬性是否反序列化到POJO中
屬性定義了類型標識符的值是否會通過JSON流成為反序列化器的一部分,默認為fale,也就是說,jackson會從JSON內容中處理和刪除類型標識符再傳遞給JsonDeserializer

@JsonSubtypes

作用於類/接口,用來列出給定類的子類,只有當子類類型無法被檢測到時才會使用它
一般是配合@JsonTypeInfo在基類上使用,比如:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include =  JsonTypeInfo.As.EXISTING_PROPERTY ,property = "contentType", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = MessageContentBack.class, name = "text/plain"),
        @JsonSubTypes.Type(value = MessageContentFile.class, name = "application/vnd.gsma.rcs-ft-http"),
        @JsonSubTypes.Type(value = MessageContentReceiveResponse.class, name = "application/vnd.gsma.botsuggestion.response.v1.0+json"),
        @JsonSubTypes.Type(value = MessageContentSharedData.class, name = "application/vnd.gsma.botsharedclientdata.v1.0+json"),
})

特別說明:

剛開始在寫代碼時,由於不熟悉jackson,include屬性選擇的是JsonTypeInfo.As.PROPERTY,發現在對它的子類進行序列化的時候,property屬性中的內容(這里是“contentType”)作為兄弟屬性被序列化了一次,即序列化后的結果中出現兩個相同的屬性“contentType”。后來再查閱資料發現JsonTypeInfo.As.PROPERTY的意思是property中的屬性作為數據的兄弟屬性會被序列化一次,而JsonTypeInfo.As.EXITING_PROPERTY則是作為POJO中已經存在的屬性被包含到序列化的結果中。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM