最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

FastJson踩坑:@JsonField在反序列化時失效的解決

 更新時間:2021年06月18日 14:06:00   作者:insaneXs  
這篇文章主要介紹了FastJson踩坑:@JsonField在反序列化時失效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

問題描述

一個對象(某個字段為枚舉類型,為了不采用默認的序列化過程,用@JSONField指定了序列化器和反序列器,過程見舊博文),將其放到JSONArray中再序列化JSONArray對象,用得到的JSON字符串再反序列化時,發(fā)現(xiàn)能夠正常反序列化出JSONArray,而對JSONArray中的某個元素再反序列化成類對象時,出錯。

示例

同樣用舊博文的示例做個簡單測試。

基本對象類Article。

public class Article {
    private String title;
    private String content;
    @JSONField(serializeUsing = AuditStatusCodec.class, deserializeUsing = AuditStatusCodec.class)
    private AuditStatus status;
    public Article(){
    }
    public Article(String title, String content, AuditStatus status){
        this.title = title;
        this.content = content;
        this.status = status;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public AuditStatus getStatus() {
        return status;
    }
    public void setStatus(AuditStatus status) {
        this.status = status;
    }
    @Override
    public String toString() {
        return "Article{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", status=" + status +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o){
            return true;
        }
        if (o == null || getClass() != o.getClass()){
            return false;
        }
        Article article = (Article) o;
        return Objects.equals(title, article.title) &&
                Objects.equals(content, article.content) &&
                status == article.status;
    }
    @Override
    public int hashCode() {
        return Objects.hash(title, content, status);
    }
}

枚舉類型AuditStatus。

public enum AuditStatus {
    /**
     * 審核中
     */
    AUDITING(1),
    /**
     * 通過
     */
    PASSED(2),
    /**
     * 失敗
     */
    FAILED(3);
    private int code;
    AuditStatus(int code){
        this.code = code;
    }
    public int getCode() {
        return code;
    }
    public static AuditStatus convert(int code){
        AuditStatus[] enums = AuditStatus.values();
        for(AuditStatus e : enums){
            if(e.code == code){
                return e;
            }
        }
        return null;
    }
}

以及序列化/反序列化器AuditStatusCodec

public class AuditStatusCodec implements ObjectSerializer, ObjectDeserializer {
    @Override
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        Object value = parser.parse();
        return value == null ? (T) value : (T) AuditStatus.convert(TypeUtils.castToInt(value));
    }
    @Override
    public int getFastMatchToken() {
        return 0;
    }
    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
        serializer.write(((AuditStatus)object).getCode());
    }
}

按照出問題的情況,寫模擬用例:

public class FastJsonTest {
    @Test
    public void deserializeTest(){
        testJSONParse();
        testJSONArrayParse();
    }
    protected static void testJSONParse(){
        System.out.println("**************Start Test JSON Parse");
        Article originalArticle = new Article("Article 1", "This is content", AuditStatus.AUDITING);
        String jsonStr = JSON.toJSONString(originalArticle);
        System.out.println("Serialize to json string: " + jsonStr);
        Article deserializeArticle = JSON.parseObject(jsonStr, Article.class);
        System.out.println("Deserialize to Java Object: " + deserializeArticle + "; and the status is " + deserializeArticle.getStatus());
        //Equals
        Assert.assertTrue(deserializeArticle.getStatus().equals(AuditStatus.AUDITING));
        Assert.assertEquals(originalArticle, deserializeArticle);
    }
    protected static void testJSONArrayParse(){
        System.out.println("**************Start Test JSONArray Parse");
        JSONArray arr = new JSONArray();
        Article originArticle = new Article("Article 1", "This is content", AuditStatus.AUDITING);
        arr.add(originArticle);
        String jsonArrStr = JSON.toJSONString(arr);
        System.out.println("Serialize to json array string: " + jsonArrStr);
        arr = JSON.parseArray(jsonArrStr);
        Article deserializeArticle = arr.getObject(0, Article.class);
        System.out.println("Deserialize to json arr, then to java object: " + deserializeArticle + "; ant the status is " + deserializeArticle.getStatus());
        //Not Equals
        Assert.assertFalse(deserializeArticle.getStatus().equals(AuditStatus.AUDITING));
        Assert.assertNotEquals(originArticle, deserializeArticle);
    }
}

看控制臺輸出的情況:

**************Start Test JSON Parse
Serialize to json string: {"content":"This is content","status":1,"title":"Article 1"}
Deserialize to Java Object: Article{title='Article 1', content='This is content', status=AUDITING}; and the status is AUDITING
**************Start Test JSONArray Parse
Serialize to json array string: [{"content":"This is content","status":1,"title":"Article 1"}]
Deserialize to json arr, then to java object: Article{title='Article 1', content='This is content', status=PASSED}; and the status is PASSED

上述代碼中testJsonParse沒有把類對象放到JSONArray中,可以從結(jié)果中看出序列化和反序列化過程均正常。

而testJSONArrayParse先把類對象放到JSONArray中,在從JSONArray中取出對象反序列化,反序列化的結(jié)果就不正常了。

疑問

為什么JSONObject和JSONArray的反序列化過程得到的結(jié)果不一致?兩者的反序列過程差異在哪?

DEBUG

遇事不決,開始DEBUG。

JSON.parseObject的流程

首先,JSON是一個門面類,提供出一些靜態(tài)的方法供外部使用。比如說parseObject()方法。其內(nèi)部會創(chuàng)建解析器DefaultJSONParser,并將解析委托給解析器執(zhí)行。

DefualtJSONParser在創(chuàng)建時接受輸入,全局配置及特性,相當于獲取到了本次解析所有的數(shù)據(jù)。同時DefualtJSONParser的內(nèi)部創(chuàng)建了一些用于解析的組件,例如JSONLexer(用于字符串解析)。解析過程在parseObject中執(zhí)行,parseObject會通過ParseConfig(保存解析配置的一個全局對象)獲取到解析器ObjectDeserializer,并由解析器處理真正的解析過程。

在通過Class獲取ObjectDeserializer時,首先會確定ParserConfig中是否緩存了對應的反序列化器,如果不存在,則會新建一個JavaBeanDeserializer(對于一般Java對象而言)。在新建過程中,會解析Class的屬性,并保存在JavaBeanInfo中。 解析器的解析過程就是對比JSON字符串中的KEY和JavaBeanInfo的過程,把對應的值反序列化出來(判斷是否有JSONField注解,并根據(jù)注解的屬性處理也在這一步),最終還原對象。

以流程圖表示上述過程:

JSONArray.getObject()

JSONArray.getObject()會先從JSONArray中獲取出Object,然后調(diào)用TypeUtils對Object通過TypeUtils.castToJavaBean()轉(zhuǎn)型。

TypeUtils通過根據(jù)需要轉(zhuǎn)型的類型從ParserConfig中獲取ObjectDeserializer反序列化器,對于普通 Java Bean 而言,是JavaBeanDeserializer。

由于JSONArray中取出的Object實際上是JSONObject對象,因此會由JavaBeanDeserializer反序列化器的createInstance()方法執(zhí)行反序列化,得到對象。

以流程圖表示上述過程:

deserialize 和 createInstance 的不同

deserialize在反序列化時,會從class上獲取更多的屬性,其中就包括JSONField注解上的信息,而createInstance獲取的信息較少,因此忽略JSONField所帶的信息,導致自定義的反序列化器在反序列化時失效。

疑惑

為什么都是反序列化過程,二者在行為和表現(xiàn)上會有所不同?官方是如何定義deserialize和createInstance的?

上述這些問題還需要查詢更多資料來明確。也希望了解緣由的讀者進行告知。

問題的解決方式

解決的辦法不先轉(zhuǎn)換成JSONArray,然后再反序列化對象。而是通過JSON.parseArray直接轉(zhuǎn)成對象的List。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java 獲取服務器真實IP的實例

    java 獲取服務器真實IP的實例

    這篇文章主要介紹了java 獲取服務器真實IP的實例的相關(guān)資料,這里提供實現(xiàn)方法幫助大家學習理解這部分內(nèi)容,需要的朋友可以參考下
    2017-08-08
  • 詳解springcloud Feign的Hystrix支持

    詳解springcloud Feign的Hystrix支持

    這篇文章主要介紹了詳解springcloud Feign的Hystrix支持,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • SpringBoot下載文件遇到文件損壞等問題解決方案

    SpringBoot下載文件遇到文件損壞等問題解決方案

    調(diào)用接口下載spring?boot工程的resources目錄下的excel模板文件,非常常見的一個文件下載功能,但是卻容易遇到很多坑,下面總結(jié)記錄下
    2023-10-10
  • java 自己實現(xiàn)DataSource實現(xiàn)實例

    java 自己實現(xiàn)DataSource實現(xiàn)實例

    這篇文章主要介紹了java 自己實現(xiàn)DataSource實現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • SparkSQl簡介及運行原理

    SparkSQl簡介及運行原理

    Spark SQL就是將SQL轉(zhuǎn)換成一個任務,提交到集群上運行,類似于Hive的執(zhí)行方式。今天通過本文給大家分享SparkSQl簡介及運行原理,感興趣的朋友跟隨小編一起看看吧
    2021-08-08
  • Mybatis select記錄封裝的實現(xiàn)

    Mybatis select記錄封裝的實現(xiàn)

    這篇文章主要介紹了Mybatis select記錄封裝的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • 關(guān)于Lombok @Data注解:簡化Java代碼的魔法棒

    關(guān)于Lombok @Data注解:簡化Java代碼的魔法棒

    Lombok庫通過@Data注解自動生成常見的樣板代碼如getter、setter、toString等,極大減少代碼量,提高開發(fā)效率,@Data注解集成了@ToString、@EqualsAndHashCode、@Getter、@Setter、@RequiredArgsConstructor等注解的功能
    2024-10-10
  • SpringBoot生成條形碼的方案詳解

    SpringBoot生成條形碼的方案詳解

    在Spring Boot, Spring Cloud 項目中整合ZXing庫來生成條形碼在特定行業(yè)也是一個常見需求,ZXing是google開源的一個功能強大的Java庫,專門用于二維碼/條形碼等的生成與解析,所以本文給大家介紹了SpringBoot生成條形碼的方案,需要的朋友可以參考下
    2024-08-08
  • Java 內(nèi)置接口 Serializable示例詳解

    Java 內(nèi)置接口 Serializable示例詳解

    這篇文章主要為大家介紹了Java 內(nèi)置接口 Serializable示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • SpringBoot淺析安全管理之Shiro框架

    SpringBoot淺析安全管理之Shiro框架

    安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Shiro框架的使用
    2022-08-08

最新評論

虞城县| 玛纳斯县| 芷江| 海阳市| 太保市| 巴楚县| 伊川县| 阳西县| 铜鼓县| 涿鹿县| 莲花县| 林州市| 江永县| 方正县| 大方县| 黑河市| 河津市| 青冈县| 阳原县| 洛浦县| 鄂伦春自治旗| 高陵县| 蕲春县| 奉新县| 晋中市| 蓬溪县| 徐闻县| 封开县| 松溪县| 尼玛县| 江永县| 云和县| 蓬莱市| 石狮市| 大竹县| 交城县| 兰坪| 海淀区| 玉门市| 金乡县| 慈利县|