jackson學習之三:常用API操作

程式設計師欣宸發表於2021-01-28

歡迎訪問我的GitHub

https://github.com/zq2599/blog_demos

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

系列文章彙總

原始碼下載

  1. 如果您不想編碼,可以在GitHub下載所有原始碼,地址和連結資訊如下表所示(https://github.com/zq2599/blog_demos):
名稱 連結 備註
專案主頁 https://github.com/zq2599/blog_demos 該專案在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該專案原始碼的倉庫地址,https協議
git倉庫地址(ssh) git@github.com:zq2599/blog_demos.git 該專案原始碼的倉庫地址,ssh協議
  1. 這個git專案中有多個資料夾,本章的應用在jacksondemo資料夾下,如下圖紅框所示:

在這裡插入圖片描述

本篇概覽

本文是《jackson學習》系列的第三篇,前面我們們學習了jackson的低階API,知道了底層原理,本篇開始學習平時最常用的基本功能,涉及內容如下:

  1. 體驗最常用的操作,內容如下圖所示:

在這裡插入圖片描述

  1. 介紹常用的可配置屬性,以便按需要來設定;
  2. 接下來進入快速瀏覽的環節,我們們一起先把各個API過一遍;

單個物件序列化

先看常用的序列化API:

  1. 物件轉字串:
String jsonStr = mapper.writeValueAsString(twitterEntry);
  1. 物件轉檔案:
mapper.writeValue(new File("twitter.json"), twitterEntry);
  1. 物件轉byte陣列:
byte[] array = mapper.writeValueAsBytes(twitterEntry);

單個物件反序列化

  1. 字串轉物件:
TwitterEntry tFromStr = mapper.readValue(objectJsonStr, TwitterEntry.class);
  1. 檔案轉物件:
TwitterEntry tFromFile = mapper.readValue(new File("twitter.json"), TwitterEntry.class);
  1. byte陣列轉物件:
TwitterEntry tFromBytes = mapper.readValue(array, TwitterEntry.class);
  1. 字串網路地址轉物件:
String testJsonDataUrl = "https://raw.githubusercontent.com/zq2599/blog_demos/master/files/twitteer_message.json";

TwitterEntry tFromUrl = mapper.readValue(new URL(testJsonDataUrl), TwitterEntry.class);

集合序列化

  1. HashMap轉字串:
String mapJsonStr = mapper.writeValueAsString(map);

集合反序列化

  1. 字串轉HashMap:
Map<String, Object> mapFromStr = mapper.readValue(mapJsonStr, new TypeReference<Map<String, Object>>() {});

JsonNode

  1. 如果您不想使用XXX.class來做反序列化,也能使用JsonNode來操作:
JsonNode jsonNode = mapper.readTree(mapJsonStr);
String name = jsonNode.get("name").asText();
int age = jsonNode.get("age").asInt();
String city = jsonNode.get("addr").get("city").asText();
String street = jsonNode.get("addr").get("street").asText();

時間欄位格式化

  1. 對於Date欄位,預設的反序列化是時間戳,可以修改配置:
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
dateMapStr = mapper.writeValueAsString(dateMap);

JSON陣列的反序列化

假設jsonArrayStr是個json陣列格式的字串:

  1. JSON陣列轉物件陣列:
TwitterEntry[] twitterEntryArray = mapper.readValue(jsonArrayStr, TwitterEntry[].class);
  1. JSON陣列轉物件集合(ArrayList):
List<TwitterEntry> twitterEntryList = mapper.readValue(jsonArrayStr, new TypeReference<List<TwitterEntry>>() {});

完整程式碼

  1. 上述所有常用API用法的完整程式碼如下:
package com.bolingcavalry.jacksondemo.databind;

import com.bolingcavalry.jacksondemo.beans.TwitterEntry;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

public class SimpleDemo {

    private static final Logger logger = LoggerFactory.getLogger(SimpleDemo.class);

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        logger.info("以下是序列化操作");

        // 物件 -> 字串
        TwitterEntry twitterEntry = new TwitterEntry();
        twitterEntry.setId(123456L);
        twitterEntry.setFromUserId(101);
        twitterEntry.setToUserId(102);
        twitterEntry.setText("this is a message for serializer test");
        twitterEntry.setLanguageCode("zh");

        String jsonStr = mapper.writeValueAsString(twitterEntry);
        logger.info("序列化的字串:{}", jsonStr);

        // 物件 -> 檔案
        mapper.writeValue(new File("twitter.json"), twitterEntry);

        // 物件 -> byte陣列
        byte[] array = mapper.writeValueAsBytes(twitterEntry);

        logger.info("\n\n以下是反序列化操作");

        // 字串 -> 物件
        String objectJsonStr = "{\n" +
                "  \"id\":1125687077,\n" +
                "  \"text\":\"@stroughtonsmith You need to add a \\\"Favourites\\\" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?\",\n" +
                "  \"fromUserId\":855523, \n" +
                "  \"toUserId\":815309,\n" +
                "  \"languageCode\":\"en\"\n" +
                "}";


        TwitterEntry tFromStr = mapper.readValue(objectJsonStr, TwitterEntry.class);
        logger.info("從字串反序列化的物件:{}", tFromStr);

        // 檔案 -> 物件
        TwitterEntry tFromFile = mapper.readValue(new File("twitter.json"), TwitterEntry.class);
        logger.info("從檔案反序列化的物件:{}", tFromStr);

        // byte陣列 -> 物件
        TwitterEntry tFromBytes = mapper.readValue(array, TwitterEntry.class);
        logger.info("從byte陣列反序列化的物件:{}", tFromBytes);

        // 字串網路地址 -> 物件
        String testJsonDataUrl = "https://raw.githubusercontent.com/zq2599/blog_demos/master/files/twitteer_message.json";

        TwitterEntry tFromUrl = mapper.readValue(new URL(testJsonDataUrl), TwitterEntry.class);
        logger.info("從網路地址反序列化的物件:{}", tFromUrl);


        logger.info("\n\n以下是集合序列化操作");

        Map<String, Object> map = new HashMap<>();
        map.put("name", "tom");
        map.put("age", 11);

        Map<String, String> addr = new HashMap<>();
        addr.put("city","深圳");
        addr.put("street", "粵海");

        map.put("addr", addr);

        String mapJsonStr = mapper.writeValueAsString(map);
        logger.info("HashMap序列化的字串:{}", mapJsonStr);

        logger.info("\n\n以下是集合反序列化操作");
        Map<String, Object> mapFromStr = mapper.readValue(mapJsonStr, new TypeReference<Map<String, Object>>() {});
        logger.info("從字串反序列化的HashMap物件:{}", mapFromStr);

        // JsonNode型別操作
        JsonNode jsonNode = mapper.readTree(mapJsonStr);
        String name = jsonNode.get("name").asText();
        int age = jsonNode.get("age").asInt();
        String city = jsonNode.get("addr").get("city").asText();
        String street = jsonNode.get("addr").get("street").asText();

        logger.info("用JsonNode物件和API反序列化得到的數:name[{}]、age[{}]、city[{}]、street[{}]", name, age, city, street);

        // 時間型別格式

        Map<String, Object> dateMap = new HashMap<>();
        dateMap.put("today", new Date());

        String dateMapStr = mapper.writeValueAsString(dateMap);
        logger.info("預設的時間序列化:{}", dateMapStr);

        // 設定時間格式
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
        dateMapStr = mapper.writeValueAsString(dateMap);
        logger.info("自定義的時間序列化:{}", dateMapStr);

        System.out.println(objectJsonStr);

        // json陣列
        String jsonArrayStr = "[{\n" +
                "  \"id\":1,\n" +
                "  \"text\":\"text1\",\n" +
                "  \"fromUserId\":11, \n" +
                "  \"toUserId\":111,\n" +
                "  \"languageCode\":\"en\"\n" +
                "},\n" +
                "{\n" +
                "  \"id\":2,\n" +
                "  \"text\":\"text2\",\n" +
                "  \"fromUserId\":22, \n" +
                "  \"toUserId\":222,\n" +
                "  \"languageCode\":\"zh\"\n" +
                "},\n" +
                "{\n" +
                "  \"id\":3,\n" +
                "  \"text\":\"text3\",\n" +
                "  \"fromUserId\":33, \n" +
                "  \"toUserId\":333,\n" +
                "  \"languageCode\":\"en\"\n" +
                "}]";

        // json陣列 -> 物件陣列
        TwitterEntry[] twitterEntryArray = mapper.readValue(jsonArrayStr, TwitterEntry[].class);
        logger.info("json陣列反序列化成物件陣列:{}", Arrays.toString(twitterEntryArray));

        // json陣列 -> 物件集合
        List<TwitterEntry> twitterEntryList = mapper.readValue(jsonArrayStr, new TypeReference<List<TwitterEntry>>() {});
        logger.info("json陣列反序列化成物件集合:{}", twitterEntryList);
    }
}
  1. 執行結果如下:
C:\jdk\bin\java.exe -javaagent:C:\sofware\JetBrains\IntelliJIDEA\lib\idea_rt.jar=64570:C:\sofware\JetBrains\IntelliJIDEA\bin -Dfile.encoding=UTF-8 -classpath C:\jdk\jre\lib\charsets.jar;C:\jdk\jre\lib\deploy.jar;C:\jdk\jre\lib\ext\access-bridge-64.jar;C:\jdk\jre\lib\ext\cldrdata.jar;C:\jdk\jre\lib\ext\dnsns.jar;C:\jdk\jre\lib\ext\jaccess.jar;C:\jdk\jre\lib\ext\jfxrt.jar;C:\jdk\jre\lib\ext\localedata.jar;C:\jdk\jre\lib\ext\nashorn.jar;C:\jdk\jre\lib\ext\sunec.jar;C:\jdk\jre\lib\ext\sunjce_provider.jar;C:\jdk\jre\lib\ext\sunmscapi.jar;C:\jdk\jre\lib\ext\sunpkcs11.jar;C:\jdk\jre\lib\ext\zipfs.jar;C:\jdk\jre\lib\javaws.jar;C:\jdk\jre\lib\jce.jar;C:\jdk\jre\lib\jfr.jar;C:\jdk\jre\lib\jfxswt.jar;C:\jdk\jre\lib\jsse.jar;C:\jdk\jre\lib\management-agent.jar;C:\jdk\jre\lib\plugin.jar;C:\jdk\jre\lib\resources.jar;C:\jdk\jre\lib\rt.jar;D:\github\blog_demos\jacksondemo\databind\target\classes;C:\Users\12167\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.11.0\jackson-databind-2.11.0.jar;C:\Users\12167\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.0\jackson-annotations-2.11.0.jar;C:\Users\12167\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.11.0\jackson-core-2.11.0.jar;C:\Users\12167\.m2\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;C:\Users\12167\.m2\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\Users\12167\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\12167\.m2\repository\commons-io\commons-io\2.7\commons-io-2.7.jar;C:\Users\12167\.m2\repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\github\blog_demos\jacksondemo\beans\target\classes com.bolingcavalry.jacksondemo.databind.SimpleDemo
2020-08-28 07:53:01 INFO  SimpleDemo:27 - 以下是序列化操作
2020-08-28 07:53:01 INFO  SimpleDemo:38 - 序列化的字串:{"id":123456,"text":"this is a message for serializer test","fromUserId":101,"toUserId":102,"languageCode":"zh"}
2020-08-28 07:53:01 INFO  SimpleDemo:47 - 

以下是反序列化操作
2020-08-28 07:53:01 INFO  SimpleDemo:60 - 從字串反序列化的物件:[Tweet, id: 1125687077, text='@stroughtonsmith You need to add a "Favourites" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?', from: 855523, to: 815309, lang: en]
2020-08-28 07:53:01 INFO  SimpleDemo:64 - 從檔案反序列化的物件:[Tweet, id: 1125687077, text='@stroughtonsmith You need to add a "Favourites" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?', from: 855523, to: 815309, lang: en]
2020-08-28 07:53:01 INFO  SimpleDemo:68 - 從byte陣列反序列化的物件:[Tweet, id: 123456, text='this is a message for serializer test', from: 101, to: 102, lang: zh]
2020-08-28 07:53:04 INFO  SimpleDemo:74 - 從網路地址反序列化的物件:[Tweet, id: 112233445566, text='this is a message from zq2599's github', from: 201, to: 202, lang: en]
2020-08-28 07:53:04 INFO  SimpleDemo:77 - 

以下是集合序列化操作
2020-08-28 07:53:04 INFO  SimpleDemo:90 - HashMap序列化的字串:{"name":"tom","addr":{"city":"深圳","street":"粵海"},"age":11}
2020-08-28 07:53:04 INFO  SimpleDemo:92 - 

以下是集合反序列化操作
2020-08-28 07:53:04 INFO  SimpleDemo:94 - 從字串反序列化的HashMap物件:{name=tom, addr={city=深圳, street=粵海}, age=11}
2020-08-28 07:53:04 INFO  SimpleDemo:103 - 用JsonNode物件和API反序列化得到的數:name[tom]、age[11]、city[深圳]、street[粵海]
2020-08-28 07:53:04 INFO  SimpleDemo:111 - 預設的時間序列化:{"today":1598572384838}
2020-08-28 07:53:04 INFO  SimpleDemo:116 - 自定義的時間序列化:{"today":"2020-08-28 07:53:04"}
{
  "id":1125687077,
  "text":"@stroughtonsmith You need to add a \"Favourites\" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?",
  "fromUserId":855523, 
  "toUserId":815309,
  "languageCode":"en"
}
2020-08-28 07:53:04 INFO  SimpleDemo:145 - json陣列反序列化成物件陣列:[[Tweet, id: 1, text='text1', from: 11, to: 111, lang: en], [Tweet, id: 2, text='text2', from: 22, to: 222, lang: zh], [Tweet, id: 3, text='text3', from: 33, to: 333, lang: en]]
2020-08-28 07:53:04 INFO  SimpleDemo:149 - json陣列反序列化成物件集合:[[Tweet, id: 1, text='text1', from: 11, to: 111, lang: en], [Tweet, id: 2, text='text2', from: 22, to: 222, lang: zh], [Tweet, id: 3, text='text3', from: 33, to: 333, lang: en]]

Process finished with exit code 0
  1. 還會產生名為twitter.json的檔案,內容如下:
{"id":123456,"text":"this is a message for serializer test","fromUserId":101,"toUserId":102,"languageCode":"zh"}

常用配置

下面是平時可能用到的自定義配置專案:

  1. 序列化結果格式化:
mapper.enable(SerializationFeature.INDENT_OUTPUT);
  1. 空物件不要丟擲異常:
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
  1. Date、Calendar等序列化為時間格式的字串(如果不執行以下設定,就會序列化成時間戳格式):
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  1. 反序列化時,遇到未知屬性不要丟擲異常:
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  1. 反序列化時,空字串對於的例項屬性為null:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
  1. 允許C和C++樣式註釋:
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
  1. 允許欄位名沒有引號(可以進一步減小json體積):
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
  1. 允許單引號:
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

特殊配置:在json物件最外層再包裹一層

  1. 最後要說的是個特殊配置,先來看看正常情況一個普通的序列化結果:
{
  "id" : 1,
  "text" : "aabbcc",
  "fromUserId" : 456,
  "toUserId" : 0,
  "languageCode" : "zh"
}
  1. 接下來我們們做兩件事,首先,是給上述json對應的例項類新增一個註解,如下圖紅框:

在這裡插入圖片描述
3. 其次,執行以下配置:

mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
  1. 然後再次執行TwitterEntry例項的序列化,得到的結果如下,可見和之前的序列化結果相比,之前的整個json都變成了一個value,此value對應的key就是註解JsonRootName的value屬性:
{
  "aaa" : {
    "id" : 1,
    "text" : "aabbcc",
    "fromUserId" : 456,
    "toUserId" : 0,
    "languageCode" : "zh"
  }
}
  • 至此,開發中常用的API和配置都已經介紹完成,希望能給您帶來一些參考,接下來的章節,我們們一起去了解另一個常用操作:jackson註解

你不孤單,欣宸原創一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 資料庫+中介軟體系列
  6. DevOps系列

歡迎關注公眾號:程式設計師欣宸

微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos

相關文章