Google Gson用法詳解


@html


1、簡介

Gson(又稱Google Gson)是Google公司發佈的一個開放源代碼的Java庫,主要用途爲序列化Java對象爲JSON字符串,或反序列化JSON字符串成Java對象。java

Gson官網:gson Gson源碼地址:google/gsongit


2、依賴

使用Maven導入依賴:github

<dependency>
 <groupId>com.google.code.gson</groupId>  <artifactId>gson</artifactId>  <version>2.8.5</version>  </dependency> 複製代碼

Gradle導入依賴:web

compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
複製代碼

3、基本用法


一、建立Gson實例

使用Gson的第一步是建立一個Gson對象,建立愛你Gson對象有兩種方式:編程

  • 使用 new Gson()
  • 建立GsonBuilder實例,使用 create() 方法

1.一、new Gson()

示例以下:json

Gson gson = new Gson();
複製代碼

1.二、GsonBuilder.build()

示例以下:數組

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create(); 複製代碼

二、Java對象-->JSON

下面會用到這個實體類:網絡

public class Employee {
 private int id;  private String firstName;  private String lastName;  private String email;  //省略getter/setter,構造方法,toSting方法 } 複製代碼

在Gson中的序列化即將Java對象轉換爲其JSON表示形式。 爲了進行序列化,首先須要一個Gson對象,該對象能夠處理轉換。 接下來,須要調用函數toJson()方法並傳入Employee對象。maven

Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
  Gson gson = new Gson();   String jsonString = gson.toJson(emp);   System.out.println(jsonString); 複製代碼

運行結果:

在這裏插入圖片描述
在這裏插入圖片描述

三、JSON-->Java對象

在Gson進行反序列指的是將JSON字符串轉換爲Java對象。 爲了進行反序列化,咱們須要使用Gson對象調用fromJson()函數,並在解析完成後傳遞兩個參數,即JSON字符串和所需的Java類型。

String jsonString = "{'id':1001, 'firstName':'Lokesh', 'lastName':'Gupta', 'email':'howtodoinjava@gmail.com'}";
  Gson gson = new Gson();   Employee empObject = gson.fromJson(jsonString, Employee.class);   System.out.println(empObject); 複製代碼

運行結果: 在這裏插入圖片描述

四、漂亮地輸出

默認狀況下,Gson以緊湊格式打印JSON,即字段名稱及其值,對象字段以及JSON輸出中數組內的對象等之間將沒有空格。

{"id":1,"firstName":"Lokesh","lastName":"Gupta", "emailId":"howtogoinjava@gmail.com"}
複製代碼

可是,這種緊湊的JSON可能很難閱讀。所以,GSON提供了一個漂亮的打印選項,能夠在其中打印JSON,以便於更加方便閱讀。

Gson gson = new GsonBuilder()
 .setPrettyPrinting()  .create();   Employee employeeObj = new Employee(1, "Lokesh", "Gupta", "howtogoinjava@gmail.com");   System.out.println(gson.toJson(employeeObj)); 複製代碼

運行結果:

在這裏插入圖片描述

五、JSON array --> Java array/list

5.1 、 JSON array -->Java對象

users.json:

[
 {  "name": "Alex",  "id": 1  },  {  "name": "Brian",  "id": 2  },  {  "name": "Charles",  "id": 3  } ] 複製代碼

User.java:

public class User {  private long id;  private String name;   public long getId() {  return id;  }  public void setId(long id) {  this.id = id;  }  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }   @Override  public String toString() {  return "User [id=" + id + ", name=" + name + "]";  } } 複製代碼

將json數組反序列化爲Java對象數組:

String userJson = "[{'name': 'Alex','id': 1}, "
 + "{'name': 'Brian','id':2}, "  + "{'name': 'Charles','id': 3}]";  Gson gson = new Gson();  User[] userArray = gson.fromJson(userJson, User[].class);  for(User user : userArray) {  System.out.println(user); } 複製代碼

運行結果: 在這裏插入圖片描述


5.2 、JSON array-->List

將json數組反序列化爲根–到Java對象列表:

String userJson = "[{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]";
  Gson gson = new Gson();   java.lang.reflect.Type userListType = new TypeToken<ArrayList<User>>() {  }.getType();   ArrayList<User> userArray = gson.fromJson(userJson, userListType);   for (User user : userArray) {  System.out.println(user);  }  複製代碼

運行結果:

在這裏插入圖片描述
在這裏插入圖片描述

5.3 、JSON array-->成員變量

若是Json數組是非根對象,則Gson能夠將JSON數組解析爲成員變量。咱們能夠按一般的方式使用fromJson()方法,將json數組解析爲所需的Java數組或列表。

department.json:

{
 "id" : 1,  "name" : "HR",  "users" : [  {  "name": "Alex",  "id": 1  },  {  "name": "Brian",  "id": 2  },  {  "name": "Charles",  "id": 3  }  ] 複製代碼

5.3.一、數組類型成員變量

Department.java:

public class Department {
 private long id;  private String name;  private User[] users;  //省略getter/setter、構造方法、toString方法 } 複製代碼

JsonArrayToMemberArray.java:

String departmentJson = "{'id' : 1, "
 + "'name': 'HR',"  + "'users' : ["  + "{'name': 'Alex','id': 1}, "  + "{'name': 'Brian','id':2}, "  + "{'name': 'Charles','id': 3}]}";  Gson gson = new Gson();  Department department = gson.fromJson(departmentJson, Department.class);  System.out.println(department); 複製代碼

運行結果:

在這裏插入圖片描述
在這裏插入圖片描述

5.3.二、List類型成員變量

將json數組反序列化爲List類型成員變量。

Department2.java:

public class Department2 {
 private long id;  private String name;  private List<User> users;  //省略getter/setter、構造方法、toString方法 } 複製代碼

轉換:

String departmentJson = "{'id' : 1, "
 + "'name': 'HR',"  + "'users' : ["  + "{'name': 'Alex','id': 1}, "  + "{'name': 'Brian','id':2}, "  + "{'name': 'Charles','id': 3}]}";   Gson gson = new Gson();   Department2 department = gson.fromJson(departmentJson, Department2.class);   System.out.println(department); 複製代碼

運行結果:

在這裏插入圖片描述

六、JSON <---->Set

6.一、Set-->JSON

使用Gson.toJson()方法將HashSet序列化爲JSON:

Set<String> userSet = new HashSet<String>();
 userSet.add("Alex");  userSet.add("Brian");  userSet.add("Charles");   Gson gson = new Gson();   String jsonString= gson.toJson(userSet);   System.out.println(jsonString); 複製代碼

運行結果:

在這裏插入圖片描述
在這裏插入圖片描述

6.二、JSON-->Set

使用Gson.fromJson()方法和TypeToken將JSON反序列化爲HashSet:

String jsonString = "['Alex','Brian','Charles','Alex']";
  Gson gson = new Gson();   java.lang.reflect.Type setType = new TypeToken<HashSet<String>>(){}.getType();   Set<String> userSet = gson.fromJson(jsonString, setType);   System.out.println(userSet); 複製代碼

運行結果: 在這裏插入圖片描述


七、Null值處理

Gson中實現的默認行爲是忽略空對象字段。

例如,若是在Employee對象中未指定電子郵件(即email爲null),則電子郵件將不會被序列化JSON輸出。Gson會忽略null字段,由於此行爲容許使用更緊湊的JSON輸出格式。


7.一、如何在序列化時容許空值

要配置Gson實例以輸出null,咱們必須使用GsonBuilder對象的serializeNulls()。

Gson gson = new GsonBuilder()
 .serializeNulls()  .create(); 複製代碼

八、版本支持

應用程序隨着時間變化,模型類也隨之變化。有時候更新/刪除字段可能會被打斷。

全部這些更改均可以使用@Since註釋進行標記,以跟蹤模型類,在這些系統使用反序列化JSON數據進行交換時,與其餘系統的應用程序交互不會中斷。

8.一、@Since註解

在Gson中,可使用@Since註釋維護同一對象的多個版本。能夠在類,字段以及未來的方法中使用此註釋。它採用單個參數– ignoreVersionsAfter。

當咱們爲Gson實例配置版本號「 M.N」時,全部標記有版本大於M.N的類字段都將被忽略。例如,若是咱們將Gson配置爲版本號「 1.2」,則全部版本號更高的字段(例如1.三、1.4…)都將被忽略。

@Since(1.2)
private String email; 複製代碼

8.二、如何使用@Since註解編寫版本化的類

在Employee類下面,咱們對三個字段進行了版本控制,即firstName,lastName和email。

public class Employee {  private Integer id;   @Since(1.0)  private String firstName;   @Since(1.1)  private String lastName;   @Since(1.2)  private String email; } 複製代碼

8.三、建立具有版本支持的Gson實例

要建立使用過@Since註解的Gson實例,須要使用GsonBuilder.setVersion()方法:

Gson gson = new GsonBuilder()
 .setVersion(1.1)  .create(); 複製代碼

8.四、實例

8.4.一、 具有版本支持的序列化

讓序列號以上的Employee對象序列化。

Employee employeeObj = new Employee(1, "Lokesh", "Gupta", "howtogoinjava@gmail.com");
 Gson gson = new GsonBuilder()  .setVersion(1.1)  .setPrettyPrinting()  .create();  System.out.println(gson.toJson(employeeObj)); 複製代碼

輸出:

{
 "id": 1,  "firstName": "Lokesh",  "lastName": "Gupta" } 複製代碼

8.4.二、具有版本支持的反序列化

咱們將JSON字符串反序列化爲版本號爲Employee的對象。

String json = "{'id': 1001, "
 + "'firstName': 'Lokesh',"  + "'lastName': 'Gupta',"  + "'email': 'howtodoinjava@gmail.com'}";  Gson gson = new GsonBuilder()  .setVersion(1.1)  .setPrettyPrinting()  .create();  Employee employeeObj = gson.fromJson(json, Employee.class);  System.out.println(employeeObj); 複製代碼

輸出:

Employee [id=1001, firstName=Lokesh, lastName=Gupta, email=null]
複製代碼

九、更改Java對象和JSON的字段名映射

在此Gson @SerializedName示例中,演示在序列化和反序列化過程當中更改json和java對象之間的字段名稱。

9.一、@SerializedName

默認狀況下,咱們假設Java模型類和JSON將具備徹底相同的字段名稱。

但有時狀況並不是如此,某些名稱有所不一樣。如今咱們必須將json中的someName映射到Java類中的someOtherName。這是@SerializedName註解用到的地方。

@SerializedName註解指示帶註解的成員變量應使用提供的名稱值做爲其字段名稱序列化爲JSON。此註解將覆蓋可能一直在使用GsonBuilder類的任何FieldNamingPolicy,包括默認的字段命名策略。

請注意,在此註解中指定的值必須是有效的JSON字段名稱。

註解包含屬性

  • value –序列化或反序列化時所需的字段名稱。
  • alternate–反序列化時字段的備用名稱。除了「值」屬性外,它還提供了更多可能的名稱。若是有多個字段匹配一個屬性,則Gson將使用最後處理的那個。

9.二、序列化期時更改字段名稱

讓咱們以只有四個字段的Employee類爲例。咱們要建立一個JSON,其中「 email」被寫爲字段名「 emailId」:

public class Employee {  private Integer id;  private String firstName;  private String lastName;   @SerializedName(value = "emailId", alternate = "emailAddress")  private String email; } 複製代碼

讓咱們序列化一個Employee實例並查看JSON輸出:

Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
 Gson gson = new GsonBuilder().setPrettyPrinting().create();  System.out.println(gson.toJson(emp)); 複製代碼

輸出:

{
 "id": 1001,  "firstName": "Lokesh",  "lastName": "Gupta",  "emailId": "howtodoinjava@gmail.com" } 複製代碼

9.三、反序列化時更改字段名稱

在將JSON反序列化爲Java類的過程當中映射不一樣的字段名稱:

Json:

{
 "id": 1001,  "firstName": "Lokesh",  "lastName": "Gupta",  "email": "howtodoinjava@gmail.com",  "emailAddress": "admin@gmail.com" } 複製代碼

Main.java:

String json = "{'id': 1001,"
 + "'firstName': 'Lokesh',"  + "'lastName': 'Gupta',"  + "'email': 'howtodoinjava@gmail.com',"  + "'emailAddress': 'admin@gmail.com'}";  Gson gson = new GsonBuilder().setPrettyPrinting().create();  Employee emp = gson.fromJson(json, Employee.class);  System.out.println(emp); 複製代碼

輸出:

Employee [id=1001, firstName=Lokesh, lastName=Gupta, email=admin@gmail.com]
複製代碼

十、排除或忽略字段

Gson容許咱們從Java類中排除或忽略不但願包含在序列化和反序列化中的字段。

Gson支持許多內置機制,用於排除頂級類,字段和字段類型。

10.一、@Expose註解

GSON @Expose註解(com.google.gson.annotations.Expose)可用於標記對象序列化或反序列化時是否公開(包括活不包括)的字段。

@Expose註釋在要顯式指定應進行序列化或反序列化的全部字段的編程方式中頗有用。

10.1.1. 怎麼用 @Expose

@Expose是可選的,並提供兩個配置參數:

  • serialize –若是爲true,則在序列化時會在JSON中寫出帶有此註解的字段。
  • deserialize –若是爲true,則從JSON反序列化帶有此註解的字段。
@Expose(serialize = false) 
private String lastName;  @Expose (serialize = false, deserialize = false) private String emailAddress; 複製代碼

10.1.二、建立Gson實例

若是咱們使用 new Gson() 建立Gson並執行toJson() 和 fromJson() 方法,則@Expose將不會對序列化和反序列化產生任何影響。要使用此批註,咱們必須使用GsonBuilder類及其excludeFieldsWithoutExposeAnnotation()方法建立Gson實例。

Gson gson = new GsonBuilder()
 .excludeFieldsWithoutExposeAnnotation()  .create(); 複製代碼

10.二、用修飾符排除字段

10.2.一、transient 字段

默認狀況下,若是咱們僅將字段標記爲瞬時態,則Gson會將字段從序列化和反序列化中排除。

請記住,它沒法阻止單向轉換。它同時阻止了二者。

transient 具備與@Expose相同的效果(serialize = false,deserialize = false)。

@Expose(serialize = false) 
private String lastName;  private transient String emailAddress; 複製代碼

10.2.二、其餘修飾符

經過使用GsonBuilder的excludeFieldsWithModifiers()方法,咱們能夠排除具備某些公共修飾符的字段。

例如,咱們要排除一個類的全部靜態成員,咱們能夠這樣建立Gson對象:

Gson gson = new GsonBuilder()
 .excludeFieldsWithModifiers(Modifier.STATIC)  .create(); 複製代碼

咱們可使用任意數量的Modifier常量來「 excludeFieldsWithModifiers」方法。例如:

Gson gson = new GsonBuilder()
 .excludeFieldsWithModifiers(Modifier.STATIC,  Modifier.TRANSIENT,  Modifier.VOLATILE)  .create(); 複製代碼

10.三、排除策略

若是以上任何一種技術都不適合咱們,那麼咱們能夠建立本身的策略。

ExclusionStrategy用於肯定是否應將字段或頂級類做爲JSON輸出/輸入的一部分進行序列化或反序列化。

  • 對於序列化,若是shouldSkipClass(Class)或shouldSkipField(fieldAttributes)方法返回true,則該類或字段類型將不屬於JSON輸出。
  • 對於反序列化,若是shouldSkipClass(Class)或shouldSkipField(fieldAttributes)方法返回true,則不會將其設置爲Java對象結構的一部分。

例如,在ExclusionStrategy定義下面,將排除全部使用@Hidden註釋註釋的字段:

//public @interface Hidden {
 // some implementation here //}  // Excludes any field (or class) that is tagged with an "@Hidden" public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {  public boolean shouldSkipClass(Class<?> clazz) {  return clazz.getAnnotation(Hidden.class) != null;  }   public boolean shouldSkipField(FieldAttributes f) {  return f.getAnnotation(Hidden.class) != null;  } } 複製代碼

要使用此排除策略,在GsonBuilder對象中進行設置:

GsonBuilder builder = new GsonBuilder();
builder.setExclusionStrategies( new HiddenAnnotationExclusionStrategy() );  Gson gson = builder.create(); 複製代碼

4、GsonBuilder

對於簡單的用例,使用'Gson gson = new Gson();' 標準配置就足夠了。 可是,若是打算自定義Gson的行爲,則可使用GsonBuilder自定義的配置來建立新的Gson實例。

GsonBuilder類提供一個.create()方法,該方法返回一個Gson實例。

Gson gson = new GsonBuilder().create(); 
複製代碼

一、GsonBuilder.setPrettyPrinting()–漂亮地打印JSON

默認狀況下,Gson將建立緊湊的JSON字符串。這對於減小經過網絡傳輸的數據量很是有用。

可是,這種緊湊的JSON對開發人員進行開發/調試應用程序時不友好。使用漂亮的打印來格式化JSON輸出:

Gson gson = new GsonBuilder()
 .setPrettyPrinting()  .create(); 複製代碼

二、FieldNamingPolicy

FieldNamingPolicy枚舉在序列化期間爲JSON字段名稱提供了幾種標準命名約定。

它有助於Gson實例將Java字段名稱正確轉換爲所需的JSON字段名稱。

注意:如下任何命名約定均不會影響以@SerializedName註釋的字段。咱們將驗證使用User類的每一個策略生成的名稱。

User.java:

public class User {  private int id;  private String first_Name;  private String lastName;  private String _email; } 複製代碼

如何使用FieldNamingPolicy:

User user = new User(1, "Lokesh", "Gupta", "admin@howtodoinjava.com");
 Gson gson = new GsonBuilder()  .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)  .setPrettyPrinting().create();  System.out.println(gson.toJson(user)); 複製代碼

如下演示每種命名策略下轉換的不一樣的名稱。


2.一、FieldNamingPolicy.IDENTITY

使用此命名策略字段名稱不變。這個是默認的策略:

{
 "id": 1,  "first_Name": "Lokesh",  "lastName": "Gupta",  "_email": "admin@howtodoinjava.com" } 複製代碼

2.二、FieldNamingPolicy.LOWER_CASE_WITH_DASHES

Gson會將Java字段名稱從其駝峯大小寫形式修改成小寫的字段名稱,其中每一個單詞都用破折號(-)分隔。

{
 "id": 1,  "first_-name": "Lokesh",  "last-name": "Gupta",  "_email": "admin@howtodoinjava.com" } 複製代碼

2.三、FieldNamingPolicy.LOWER_CASE_WITH_DOTS

Gson會將Java字段名稱從其駝峯大小寫形式修改成小寫的字段名稱,其中每一個單詞都用點(.)分隔:

{
 "id": 1,  "first_.name": "Lokesh",  "last.name": "Gupta",  "_email": "admin@howtodoinjava.com" } 複製代碼

2.四、FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES

Gson會將Java字段名稱從其駝峯大小寫形式修改成小寫的字段名稱,其中每一個單詞都用下劃線(_)分隔。

{
 "id": 1,  "first__name": "Lokesh",  "last_name": "Gupta",  "_email": "admin@howtodoinjava.com" } 複製代碼

2.五、 FieldNamingPolicy.UPPER_CAMEL_CASE

Gson將確保序列化爲JSON格式的Java字段名稱的第一個「字母」大寫:

{
 "Id": 1,  "First_Name": "Lokesh",  "LastName": "Gupta",  "_Email": "admin@howtodoinjava.com" } 複製代碼

2.六、FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES

Gson將確保在將Java字段名稱的第一個「字母」序列化爲JSON格式時將其大寫,而且單詞之間將使用空格分隔:

{
 "Id": 1,  "First_ Name": "Lokesh",  "Last Name": "Gupta",  "_Email": "admin@howtodoinjava.com" } 複製代碼

三、GsonBuilder.serializeNulls()——空值的序列化

默認狀況下,Gson會在序列化過程當中忽略null值。可是,有時咱們想序列化具備空值的字段,以便它必須出如今JSON中。爲此,可使用serializeNulls()方法:

Employee employeeObj = new Employee(1, "Lokesh", "Gupta", null);
 Gson gson = new GsonBuilder()  .serializeNulls()  .setPrettyPrinting().create();  System.out.println(gson.toJson(employeeObj)); 複製代碼

輸出:

{
 "id": 1,  "firstName": "Lokesh",  "lastName": "Gupta",  "emailId": null } 複製代碼

四、GsonBuilder.setExclusionStrategies()

ExclusionStrategy用於肯定是否應將字段或頂級類做爲JSON輸出/輸入的一部分進行序列化或反序列化。

  • 對於序列化,若是shouldSkipClass(Class)方法返回true,則該類或字段類型將不會在JSON中輸出。
  • 對於反序列化,若是shouldSkipClass(Class)返回true,則不會將其設置爲Java對象結構的一部分。

shouldSkipField(attribute)方法也是相同的規則。

在下面的示例中,使用@NPI註解和屬於Account類的實例的成員字段不會進行序列化和反序列化。

Gson gson = new GsonBuilder()
 .setExclusionStrategies(new ExclusionStrategy() {  @Override  public boolean shouldSkipField(FieldAttributes f) {  return f.getAnnotation(NPI.class) != null;  }   @Override  public boolean shouldSkipClass(Class<?> clazz) {  return clazz.getAnnotation(Account.class) != null;  }  })  .setPrettyPrinting()  .create(); 複製代碼

五、GsonBuilder.setLenient()——寬鬆的JSON語法規則

在反序列化期間,Gson使用了一個寬鬆的JsonReader類。這意味着它僅接受兼容的JSON輸入。

若是JSON違反結構規則之一,它將拋出MalformedJsonException。若是咱們將lenient設置爲true,則它將忽視某些違規行爲,並嘗試讀取格式不正確的JSON。

Gson gson = new GsonBuilder()
 .setLenient()  .setPrettyPrinting().create(); 複製代碼

5、JsonReader

使用Gson JsonReader類,該類是基於拉式的流JSON解析器。它有助於將JSON做爲令牌流讀取。

一、JsonReader

  • JsonReader是流式JSON解析器,也是pull parser的示例。pull parser解析JSON令牌並將其推送到事件處理程序中。
  • 它有助於讀取JSON(RFC 7159)編碼值做爲令牌流。
  • 它讀取字面值(字符串,數字,布爾值和null)以及對象和數組的開始和結束定界符。
  • 令牌以深度優先順序遍歷,與JSON文檔中出現的順序相同。

二、Tokens

在流模式下,每一個JSON數據都被視爲一個單獨的令牌。

當咱們使用JsonReader對其進行處理時,每一個令牌將被順序處理。例如,

{
 "name":"Lokesh" } 複製代碼

在使用JsonReader進行解析時,以上JSON將生成4個令牌:

  • Token 1 = {
  • Token 2 = name
    • Token 3 = Lokesh
  • Token 4 = }

三、如何建立GSON JsonReader

咱們可使用它的簡單構造函數建立一個JsonReader實例,該實例接受java.io.Reader類型的輸入流。

String json = "{}";
JsonReader jsonReader = new JsonReader( new StringReader(json) ); 複製代碼

咱們能夠根據JSON流的來源使用如下閱讀器之一:

  • BufferedReader
  • LineNumberReader
  • CharArrayReader
  • InputStreamReader
  • FileReader
  • FilterReader
  • PushbackReader
  • PipedReader
  • StringReader

四、讀取JSON流

建立包含有效JSON源的JsonReader以後,咱們能夠開始遍歷流令牌並查看令牌值。

如下是使用JsonReader以令牌形式讀取簡單JSON的示例:

import java.io.IOException;
import java.io.StringReader;  import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken;  public class Main {  public static void main(String[] args) throws Exception  {   String json = "{'id': 1001,'firstName': 'Lokesh','lastName': 'Gupta','email': null}";   JsonReader jsonReader = new JsonReader(new StringReader(json));  jsonReader.setLenient(true);   try  {  while (jsonReader.hasNext())  {  JsonToken nextToken = jsonReader.peek();   if (JsonToken.BEGIN_OBJECT.equals(nextToken)) {   jsonReader.beginObject();   } else if (JsonToken.NAME.equals(nextToken)) {   String name = jsonReader.nextName();  System.out.println("Token KEY >>>> " + name);   } else if (JsonToken.STRING.equals(nextToken)) {   String value = jsonReader.nextString();  System.out.println("Token Value >>>> " + value);   } else if (JsonToken.NUMBER.equals(nextToken)) {   long value = jsonReader.nextLong();  System.out.println("Token Value >>>> " + value);   } else if (JsonToken.NULL.equals(nextToken)) {   jsonReader.nextNull();  System.out.println("Token Value >>>> null");   } else if (JsonToken.END_OBJECT.equals(nextToken)) {   jsonReader.endObject();   }  }  } catch (IOException e) {  e.printStackTrace();  } finally {  jsonReader.close();  }  } } 複製代碼

輸出:

Token KEY >>>> id
Token Value >>>> 1001  Token KEY >>>> firstName Token Value >>>> Lokesh  Token KEY >>>> lastName Token Value >>>> Gupta  Token KEY >>>> email Token Value >>>> null 複製代碼

在上面的示例中:

  • 若是JsonReader的hasNext()方法具備更多令牌,則返回true。
  • peek()方法返回下一個JSON令牌,但不移至該令牌。
  • 隨後屢次調用peek()將返回相同的JSON令牌。
  • 可使用JsonToken類的常量檢查返回令牌的類型。
  • 使用beginArray()和endArray()方法檢查數組的左括號和右括號「 [」和「]」。使用beginObject()和endObject()方法檢查對象的左括號和右括號「 {」和「}」。
  • 令牌的密鑰爲JsonToken.NAME類型。使用nextName()方法獲取密鑰名稱。
  • 肯定令牌的類型後,使用諸如nextLong(),nextString(),nextInt()等方法獲取令牌的值。可使用nextNull()或skipValue()使用空文字。
  • 全部next ....()方法都返回當前標記的值,並將內部指針移至下一個。
  • 當遇到未知名稱時,嚴格的解析器應該失敗,並帶有異常。寬大的解析器應調用skipValue()以遞歸地跳過該值的嵌套令牌,不然可能會發生衝突。

6、JsonParser

Gson JsonParser用於將Json數據解析爲JsonElement的解析樹,從而解析爲JsonObject。

JsonObject可用於使用JSON字符串中的相應鍵來訪問值。

一、建立JsonParser

JsonParser類只有一個默認構造函數,而且不須要任何參數或配置。

JsonParser parser = new JsonParser();
複製代碼

二、轉化JSON

JsonParser類提供3種方法來提供JSON做爲源並將其解析爲JsonElements樹。

  • JsonElement parse(JsonReader json)–使用JsonReader讀取JSON做爲令牌流,並從JSON流中返回下一個值做爲分析樹。
  • JsonElement parse(java.io.Reader json)–使用指定的閱讀器讀取JSON並將JSON字符串解析爲解析樹。
  • JsonElement parse(java.lang.String json)–將指定的JSON字符串解析爲解析樹。

若是指定的文本不是有效的JSON,則這三個方法都將拋出JsonParseException和JsonSyntaxException。


三、 JsonElement, JsonObject 和JsonArray

在JsonElement樹中解析了JSON字符串後,咱們就可使用它的各類方法來訪問JSON數據元素。

例如,使用一種類型檢查方法找出它表明什麼類型的JSON元素:

jsonElement.isJsonObject();
jsonElement.isJsonArray(); jsonElement.isJsonNull(); jsonElement.isJsonPrimitive(); 複製代碼

咱們可使用相應的方法將JsonElement轉換爲JsonObject和JsonArray:

JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonArray jsonArray = jsonElement.getAsJsonArray(); 複製代碼

一旦有了JsonObject或JsonArray實例,就可使用其get()方法從中提取字段。


四、Gson JsonParser 示例

使用JsonParser將JSON解析爲JsonElement(和JsonObject),並使用鍵獲取JSON值:

import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonParser;  public class Main {  public static void main(String[] args) throws Exception  {  String json = "{'id': 1001, "  + "'firstName': 'Lokesh',"  + "'lastName': 'Gupta',"  + "'email': 'howtodoinjava@gmail.com'}";   JsonElement jsonElement = new JsonParser().parse(json);   JsonObject jsonObject = jsonElement.getAsJsonObject();   System.out.println( jsonObject.get("id") );  System.out.println( jsonObject.get("firstName") );  System.out.println( jsonObject.get("lastName") );  System.out.println( jsonObject.get("email") );  } } 複製代碼

輸出:

1001
"Lokesh" "Gupta" "howtodoinjava@gmail.com" 複製代碼

五、使用fromJson() 獲取JsonObject

咱們可使用Gson實例及其fromJson()方法來得到相同的結果:

String json = "{'id': 1001, "
 + "'firstName': 'Lokesh',"  + "'lastName': 'Gupta',"  + "'email': 'howtodoinjava@gmail.com'}";  JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);  System.out.println(jsonObject.get("id")); System.out.println(jsonObject.get("firstName")); System.out.println(jsonObject.get("lastName")); System.out.println(jsonObject.get("email")); 複製代碼

輸出:

String json = "{'id': 1001, "
 + "'firstName': 'Lokesh',"  + "'lastName': 'Gupta',"  + "'email': 'howtodoinjava@gmail.com'}";  JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);  System.out.println(jsonObject.get("id")); System.out.println(jsonObject.get("firstName")); System.out.println(jsonObject.get("lastName")); System.out.println(jsonObject.get("email")); 複製代碼

六、迭代JSON樹結構

這是一個完整的示例,展現瞭如何迭代從JsonReader得到的JsonElement:

JsonParser parser = new JsonParser();
 String json = "{ \"f1\":\"Hello\",\"f2\":{\"f3:\":\"World\"}}";  JsonElement jsonTree = parser.parse(json);  if(jsonTree.isJsonObject()){  JsonObject jsonObject = jsonTree.getAsJsonObject();   JsonElement f1 = jsonObject.get("f1");   JsonElement f2 = jsonObject.get("f2");   if(f2.isJsonObject()){  JsonObject f2Obj = f2.getAsJsonObject();   JsonElement f3 = f2Obj.get("f3");  }  } 複製代碼

7、自定義序列化和反序列化

Gson在默認序列化和反序列化方面提供了很是出色的功能。

不過,咱們可能會遇到默認和內置自定義選項沒法解決咱們問題的狀況。在這種狀況下,咱們能夠經過兩個接口JsonSerializer和JsonDeserializer使用自定義序列化和反序列化。

一、自定義序列化

1.一、JsonSerializer接口

JsonSerializer.java:

public interface JsonSerializer<T> {  public JsonElement serialize(T value, Type type,  JsonSerializationContext jsonSerializationContext) {  } } 複製代碼

爲Json建立自定義序列化程序後,咱們還須要經過GsonBuilder.registerTypeAdapter(Type,Object)註冊該序列化程序。

當Gson遇到指定類型的字段時,它會在序列化期間調用其回調方法serialize()。


1.二、自定義序列化示例

假設咱們遇到一種狀況,咱們必須將Java對象序列化爲json,這樣全部布爾值都應寫爲1或0,而不是打印true或false。

讓咱們爲該要求編寫自定義序列化程序。

BooleanSerializer.java:

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer;  public class BooleanSerializer implements JsonSerializer<Boolean> {   public JsonElement serialize(Boolean aBoolean, Type type,  JsonSerializationContext jsonSerializationContext)  {  if(aBoolean){  return new JsonPrimitive(1);  }  return new JsonPrimitive(0);  } } 複製代碼

讓咱們編寫一個程序,使用registerTypeAdapter()註冊JsonSerializer實例,並使用該程序將Java對象序列化爲json。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;  public class Main {  public static void main(String[] args) throws Exception  {  Employee emp = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com", true);   Gson gson = new GsonBuilder()  .registerTypeAdapter(Boolean.class, new BooleanSerializer())  .setPrettyPrinting()  .create();   String json = gson.toJson(emp);   System.out.println(json);  } } 複製代碼

注意程序輸出,鍵「 active」的值被序列化爲1:

{
 "id": 1,  "firstName": "Lokesh",  "lastName": "Gupta",  "email": "howtodoinjava@gmail.com",  "active": 1 } 複製代碼

二、自定義反序列化

2.一、JsonDeserializer接口

定製反序列化器必須實現JsonDeserializer接口。JsonDeserializer接口以下所示:

JsonDeserializer.java:

public interface JsonDeserializer<T> {  public Boolean deserialize(JsonElement jsonElement,  Type type, JsonDeserializationContext jsonDeserializationContext)  throws JsonParseException; } 複製代碼

爲Json建立自定義反序列化器以後,咱們還須要經過GsonBuilder.registerTypeAdapter(Type,Object)註冊此反序列化器。

當Gson遇到指定類型的字段時,它會在序列化期間調用其回調方法deserialize()。

2.二、自定義反序列化示例

假設某些服務將日期字段分別分爲天,月和年等部分分別返回給咱們。在JSON字符串中,它們可能有意義,可是在Java中,它們只有做爲單個java.time.LocalDate對象的一部分時纔有意義。

employee.json:

{
 "id": 1,  "firstName": "Lokesh",  "lastName": "Gupta",  "email": "howtodoinjava@gmail.com",  "day": 11,  "month": 8,  "year": 2019 } 複製代碼

咱們要自定義反序列化並將最後三個字段組合爲LocalDate對象。

咱們的Employee看起來像這樣。包括必要的getter和setter以及構造函數。

Employee.java:

public class Employee {  private Integer id;  private String firstName;  private String lastName;  private String email;  private LocalDate dob; } 複製代碼

自定義反序列化器類以下所示:

EmployeeDeserializer.java:

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException;  public class EmployeeDeserializer implements JsonDeserializer<Employee> {  @Override  public Employee deserialize(JsonElement json, Type typeOfT,  JsonDeserializationContext context) throws JsonParseException  {  JsonObject jsonObject = json.getAsJsonObject();   LocalDate localDate = LocalDate.of(  jsonObject.get("year").getAsInt(),  jsonObject.get("month").getAsInt(),  jsonObject.get("day").getAsInt()  );   return new Employee(  jsonObject.get("id").getAsInt(),  jsonObject.get("firstName").getAsString(),  jsonObject.get("lastName").getAsString(),  jsonObject.get("email").getAsString(),  localDate);  } } 複製代碼

註冊反序列化器,而後將給定的JSON解析爲java對象:

Main.java:

public class Main {  public static void main(String[] args) throws Exception  {  String json = "{'id': 1001,"  + "'firstName': 'Lokesh',"  + "'lastName': 'Gupta',"  + "'email': 'howtodoinjava@gmail.com', "  + "'day': 11, "  + "'month': 8, "  + "'year': 2019}";   Gson gson = new GsonBuilder()  .registerTypeAdapter(Employee.class, new EmployeeDeserializer())  .create();   Employee employee = gson.fromJson(json, Employee.class);   System.out.println(employee);  } } 複製代碼

注意程序輸出將3個單獨的字段組合到單個LocalDate對象中:

Employee [id=1001, 
 firstName=Lokesh,  lastName=Gupta,  email=howtodoinjava@gmail.com,  dob=2019-08-11] 複製代碼



參考: 【1】:Gson 【2】:Gson – Introduction 【3】:Gson – Installation 【4】:GSON - Gson 【5】:GSON – Serialize and Deserialize JSON 【6】:Gson – Pretty Printing for JSON Output 【7】:GSON – Parse JSON array to Java array or list 【8】:GSON – Serialize and deserialize JSON to Set 【9】:Gson – GsonBuilder Configuration Examples 【10】:Gson @Since – Version Support 【11】:Gson @SerializedName 【12】:Gson – JsonReader 【13】:Gson – JsonReader 【14】:Gson – JsonParser 【15】:GSON - JsonParser

本文使用 mdnice 排版

相關文章
相關標籤/搜索