1. 程式人生 > >Jackson實現序列化和反序列化

Jackson實現序列化和反序列化

簡介

通俗的來說,Jackson是一個 Java 用來處理 JSON 格式資料的類庫,其效能非常好。Jackson具有比較高的序列化和反序列化效率,據測試,無論是哪種形式的轉換,Jackson > Gson > Json-lib,而且Jackson的處理能力甚至高出Json-lib近10倍左右,且正確性也十分高。

使用

Jackson提供了很多類和方法,而在序列化和反序列化中使用的最多的類則是ObjectMapper這個類,此類比較類似於Json-lib中JsonObject和ArrayObject。此類中提供了readTree(),readValue(),writeValueAsString()等方法用於轉換。

1 常用註解

1、 @JsonProperty 此註解用於屬性上,作用是把該屬性的名稱序列化為另外一個名稱,如把testPwd屬性序列化為pwd,@JsonProperty(value="pwd")。

2@JsonPropertyOrder
作用在類上,被用來指明當序列化時需要對屬性做排序,它有2個屬性一個是alphabetic:布林型別,表示是否採用字母拼音順序排序,預設是為false,即不排序。如@JsonPropertyOrder(alphabetic=true)。

3@JsonInclude
是用在實體類的方法類的頭上 作用是實體類的引數查詢到的為null的不顯示,比如說你想傳一些json資料到前臺,但是不想傳值為null

的資料,就可以使用該標籤。如@JsonInclude(JsonInclude.Include.NON_NULL)

4@JsonIgnoreProperties
可以註明是想要忽略的屬性列表如@JsonIgnoreProperties({"name","age","title"}),也可以註明過濾掉未知的屬性如@JsonIgnoreProperties(ignoreUnknown=true),@JsonIgnore表示忽略當前屬性。

5@JsonFormat
用在屬性和方法上,可以方便的進行格式轉換,如把Date轉換為我們要的模式@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")。

6@JsonUnwrapped
當實體類中成員屬性是一個類的物件時候,忽略包裝。直接顯示屬性。

2 序列化

/**
 * 測試使用者類
 *
 * @author 楊小華
 * @create 2017-09-27 9:39
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder(alphabetic=true)
public class User{
  /**
   * id
   * 不JSON序列化id 
   */
  @JsonIgnore
  private Integer id;
  /**
   * 暱稱
   */
  private String name;
  /**
   * 密碼
   * 序列化testPwd屬性為pwd
   */
  @JsonProperty("pwd")
  private String testPwd;

  /**
   * 註冊時間
   * 格式化日期屬性  
   */
  @JsonFormat(pattern = "yyyy-MM-dd")
  private Date time;
2.1 對自定義類的序列化
/**
   * @desc JAVA物件和集合轉JSON[JSON序列化]
   * @author 楊小華
   * @create 2017/9/27 10:15
   **/
  @Test
  public void write() {
    User user = new User();
    user.setId(1);
    user.setName("測試");
    user.setTestPwd("123456");
    user.setTime(new Date());
    List<String> jsonList = new ArrayList<String>();
    jsonList.add("王大錘");
    jsonList.add("王尼瑪");
    ObjectMapper objectMapper = new ObjectMapper();
    try {
      String json = objectMapper.writeValueAsString(user);
      System.out.printf(json);
      String list = objectMapper.writeValueAsString(jsonList);
      System.out.printf(list);
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
  }

輸出結果:
{"name":"測試","time":"2017-09-27","pwd":"123456"}
["大錘","二錘"]
2.2 另一種序列化方法

objectMapper.getFactory().createGenerator()此方法不僅可以將Json直接寫入網路流,還可以將Json寫入檔案流或者記憶體流。所以用途更廣。

/**
 * @desc 另一種序列化方法
 * @author 楊小華
 * @create 2017/9/27 10:30
 **/
@Test
public void jsonGenerator() {
  ObjectMapper objectMapper = new ObjectMapper();
  User user = new User();
  user.setId(1);
  user.setName("測試");
  user.setTestPwd("123456");
  user.setTime(new Date());
  try {
    JsonGenerator jsonGenerator = objectMapper.getFactory().createGenerator(System.out, JsonEncoding.UTF8);
    jsonGenerator.writeObject(user);
  } catch (IOException e) {
    e.printStackTrace();
  }
}

輸出結果:{"name":"測試","pwd":"123456","time":"2017-09-27"}

3 反序列化

3.1 一次性反序列化

此方法中主要利用ObjectMapper提供的<T> readValue(String content, Class<T> valueType)方法。此方法需要輸入Json串以及對應的需要填充的類的Class,返回填充後的類。將Json串解析到自定義類中。

**
 * @desc JSON轉Java類[JSON反序列化]
 * @author 楊小華
 * @create 2017/9/27 10:17
 **/
@Test
public void read() {
  String json = "{\"name\":\"測試\",\"time\":\"2017-09-27\",\"pwd\":\"123456\"}";
  ObjectMapper objectMapper = new ObjectMapper();
  try {
    User user = objectMapper.readValue(json, User.class);
    System.out.printf(user.getName());
  } catch (IOException e) {
    e.printStackTrace();
  }
}

輸出結果:
測試

/**
 * @desc JSON轉Map類[JSON反序列化]
 * @author 楊小華
 * @create 2017/9/27 10:43
 **/
@Test
public void jsonMap() {
  ObjectMapper objectMapper = new ObjectMapper();
  String json = "{\"error\":0,\"data\":{\"name\":\"ABC\",\"age\":20,\"phone\":{\"home\":\"abc\",\"mobile\":\"def\"},\"friends\":[{\"name\":\"DEF\",\"phone\":{\"home\":\"hij\",\"mobile\":\"klm\"}}," +
          "{\"name\":\"GHI\",\"phone\":{\"home\":\"nop\",\"mobile\":\"qrs\"}}]},\"other\":{\"nickname\":[]}}";
  try {
    Map<String, Map<String, Object>> map = objectMapper.readValue(json, Map.class);
    System.out.printf(map.get("error") + "\n");
    System.out.printf(map.get("data").get("phone") + "");
  } catch (IOException e) {
    e.printStackTrace();
  }
}

輸出結果:
0
{home=abc, mobile=def}

3.2 漸次反序列化

此方法更靈活,可以只將使用者感興趣的Json串資訊值提取出來。主要利用ObjectMapper提供的readTree和Jackson提供的JsonNode類來實現(此方法類似於XML解析中的DOM方式解析,其好處是結構明細,便於提取想要的資訊。當然,其缺點也一樣:耗時費空間)。

/**
 * @desc 漸次反序列化
 * @author 楊小華
 * @create 2017/9/27 11:04
 **/
@Test
public void jsonTree() {
  ObjectMapper objectMapper = new ObjectMapper();
  String test = "{\"results\":[{\"objectID\":357,\"geoPoints\":[{\"x\":504604.59802246094,\"y\":305569.9150390625}]},{\"objectID\":358,\"geoPoints\":[{\"x\":504602.2680053711,\"y\":305554.43603515625}]}]}";
  try {
    JsonNode jsonNode = objectMapper.readTree(test);//將Json串以樹狀結構讀入記憶體
    JsonNode contents = jsonNode.get("results");//得到results這個節點下的資訊
    for (int i = 0; i < contents.size(); i++) {
      System.out.printf(contents.get(i).get("objectID").intValue() + "\n");
      JsonNode geoContent = contents.get(i).get("geoPoints");//得到geoPoints這個節點下的資訊
      for (int j = 0; j < geoContent.size(); j++) {
        System.out.printf(geoContent.get(j).get("x").doubleValue() + "\n");
        System.out.printf(geoContent.get(j).get("y").decimalValue() + "\n");
      }
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
}

總結

Jackson關於Json的操作主要如上所示,其方法使用起來很便利,而且也很靈活,即提供了一次性完成的操作,也提供了可以按需讀取資訊的操作。並且Jackson的功能很齊全,可以對序列化和反序列化進行多種細節的控制,例如註解功能和對於Hibernate的延遲注入功能以及設定時間格式功能等,因為這些功能目前不太需要,所以仔細研究留待以後。同時,Jackson還支援對XML的一系列序列化和反序列化的操作,其思路與解析Json的大致相同。
對於Jackson目前的缺點,網上有人測試所比Json-lib更佔記憶體一些。而利用空間換時間,一般是值得的。