jackson學習之四:WRAP_ROOT_VALUE(root物件)

wyfem發表於2021-09-09

歡迎訪問我的GitHub

github.com/zq2599/blog_demos

內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;

本篇概覽

本文是《jackson學習》系列的第四篇,前面學習了常用API,可以執行最基本的序列化和反序列化操作,接下來要學習的就是jackson強大的註解能力,本篇要學的是root物件特性,主要內容如下:

  1. 關於root物件
  2. 測試用的POJO類
  3. 序列化實戰
  4. 反序列化實戰

關於root物件(WRAP_ROOT_VALUE)

  1. 對於只有idname兩個欄位的POJO例項來說,正常的序列化結果如下:
{
  "id" : 1,
  "name" : "book"
}
  1. jackson在序列化時,可以在上述json外面再包裹一層,官方叫做WRAP_ROOT_VALUE,本文中叫做root物件,如下所示,整個json的只有一個鍵值對,key是aaabbbccc,value內部才是POJO例項的id和name欄位的值:
{
  "aaabbbccc" : {
    "id" : 2,
    "name" : "food"
  }
}

提前小結

root物件特性提前做個小結,這樣如果您時間有限,僅看這一節即可:

  • 先看序列化場景:
  1. 執行下面程式碼,jackson在序列化時會增加root物件:
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
  1. root物件的key,預設是例項的類名,如果例項有JsonRootName註解,就是該註解的value值;
  2. root物件的value如下所示,相當於不支援root物件時的序列化結果
{
  "id" : 1,
  "name" : "book"
}
  • 再看反序列化場景:
  1. 執行下面程式碼,jackson在反序列化時會先解析root物件:
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
  1. root物件的key,預設是例項的類名,如果例項有JsonRootName註解,就是該註解的value值;
  2. root物件的value如下所示,相當於不支援root物件時用來反序列化的json字串
{
  "id" : 1,
  "name" : "book"
}

準備兩個POJO類

用對比的方式可以更清楚瞭解JsonRootName的作用,接下來的學習我們們準備兩個POJO類,一個沒有JsonRootName註解,另一個有JsonRootName註解:

  1. 名為Order1.java的,沒有JsonRootName註解:
public class Order1 {
    private int id;
    private String name;
	// 省去get、set、toString方法
	...
}
  1. 名為Order2.java的,有JsonRootName註解,value值為aaabbbccc
import com.fasterxml.jackson.annotation.JsonRootName;

@JsonRootName(value = "aaabbbccc")
public class Order2 {
	private int id;
    private String name;
	// 省去get、set、toString方法
	...
}
  • 可見Order1和Order2的程式碼是一致的,唯一的不同是Order2帶有註解JsonRootName;

序列化

  1. 需要設定WRAP_ROOT_VALUE屬性,jackson才會支援root物件,JsonRootName註解才會發揮作用,設定程式碼如下:
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
  1. 寫一段程式碼,在不開啟WRAP_ROOT_VALUE屬性的時候執行序列化,再開啟WRAP_ROOT_VALUE屬性執行序列化,對比試試:
public static void main(String[] args) throws Exception {
        // 例項化Order1和Order2
        Order1 order1 = new Order1();
        order1. setId(1);
        order1.setName("book");

        Order2 order2 = new Order2();
        order2. setId(2);
        order2.setName("food");

        // 沒有開啟WRAP_ROOT_VALUE的時候
        logger.info("沒有開啟WRAP_ROOT_VALUEn");
        ObjectMapper mapper1 = new ObjectMapper();
        // 美化輸出
        mapper1.enable(SerializationFeature.INDENT_OUTPUT);

        logger.info("沒有JsonRootName註解類,序列化結果:nn{}nn", mapper1.writeValueAsString(order1));
        logger.info("有JsonRootName註解的類,序列化結果:nn{}nnnn", mapper1.writeValueAsString(order2));

        // 開啟了WRAP_ROOT_VALUE的時候
        logger.info("開啟了WRAP_ROOT_VALUEn");
        ObjectMapper mapper2 = new ObjectMapper();
        // 美化輸出
        mapper2.enable(SerializationFeature.INDENT_OUTPUT);
        // 序列化的時候支援JsonRootName註解
        mapper2.enable(SerializationFeature.WRAP_ROOT_VALUE);

        logger.info("沒有JsonRootName註解類,序列化結果:nn{}nn", mapper2.writeValueAsString(order1));
        logger.info("有JsonRootName註解的類,序列化結果:nn{}", mapper2.writeValueAsString(order2));
    }
  1. 執行結果如下,JsonRootName在序列化時的作用一目瞭然:指定了root物件的key:

圖片描述

反序列化(預設設定)

  1. 在沒有做任何設定的時候,下面這個字串用來反序列化成Order2物件,會成功嗎?
{
  "id" : 2,
  "name" : "food"
}
  1. 試了下是可以的:

圖片描述
3. 那下面這個字串能反序列化成Order2物件嗎?

{
  "aaabbbccc" : {
    "id" : 2,
    "name" : "food"
  }
}
  1. 程式碼和結果如下圖所示,反序列化時jackson並不認識aaabbbccc這個key,因為jackson此時並不支援root物件:

圖片描述

  • 小結:預設情況下,反序列化時json字串不能有root物件;

反序列化(開啟UNWRAP_ROOT_VALUE屬性)

  1. 如果開啟了UNWRAP_ROOT_VALUE屬性,用於反序列化的json字串就必須要有root物件了,開啟UNWRAP_ROOT_VALUE屬性的程式碼如下:
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
  1. 程式碼和結果如下圖,可見帶有root物件的json字串,可以反序列化成功,root物件的key就是JsonRootName註解的value屬性:

圖片描述
3. 值得注意的是,上述json字串中,root物件的key為aaabbbccc,這和Order2的JsonRootName註解的value值是一致的,如果不一致就會反序列化失敗,如下圖:

圖片描述

  • 至此,jackson的WRAP_ROOT_VALUE特性就學習完成了,在web開發時這是個很常用的功能,用於在最外面包裹一層,以便整體上新增額外的內容,希望能給您帶來參考;

我是欣宸,期待與您一同暢遊Java世界…

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2894/viewspace-2797976/,如需轉載,請註明出處,否則將追究法律責任。

相關文章