天天看點

Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

文章目錄

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

Gson官網:

gson

Gson源碼位址:

google/gson

使用Maven導入依賴:

<dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.5</version>
    </dependency>      

Gradle導入依賴:

compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'      

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

  • 使用 new Gson()
  • 建立GsonBuilder執行個體,使用 create() 方法

示例如下:

Gson gson = new Gson();      

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();      

2、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對象。

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

運作結果:

Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

3、JSON–>Java對象

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

String jsonString = "{'id':1001, 'firstName':'Lokesh', 'lastName':'Gupta', 'email':'[email protected]'}";
        
        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":"[email protected]"}      

但是,這種緊湊的JSON可能很難閱讀。是以,GSON提供了一個漂亮的列印選項,可以在其中列印JSON,以便于更加友善閱讀。

Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();
        
        Employee employeeObj = new Employee(1, "Lokesh", "Gupta", "[email protected]");
        
        System.out.println(gson.toJson(employeeObj));      
Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

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);
        }
      
Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

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
        }
    ]      

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);      
Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

将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);      
Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

6.1、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.2、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);      
Google Gson用法詳解一、簡介二、依賴三、基本用法四、GsonBuilder五、JsonReader六、JsonParser七、自定義序列化和反序列化

Gson中實作的預設行為是忽略空對象字段。

例如,如果在Employee對象中未指定電子郵件(即email為null),則電子郵件将不會被序列化JSON輸出。Gson會忽略null字段,因為此行為允許使用更緊湊的JSON輸出格式。

要配置Gson執行個體以輸出null,我們必須使用GsonBuilder對象的serializeNulls()。

Gson gson = new GsonBuilder()
        .serializeNulls()
        .create();      

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

所有這些更改都可以使用@Since注釋進行标記,以跟蹤模型類,在這些系統使用反序列化JSON資料進行交換時,與其他系統的應用程式互動不會中斷。

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

當我們為Gson執行個體配置版本号“ M.N”時,所有标記有版本大于M.N的類字段都将被忽略。例如,如果我們将Gson配置為版本号“ 1.2”,則所有版本号更高的字段(例如1.3、1.4…)都将被忽略。

@Since(1.2)
private String email;      

在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;
}      

要建立使用過@Since注解的Gson執行個體,需要使用GsonBuilder.setVersion()方法:

Gson gson = new GsonBuilder()
            .setVersion(1.1)
            .create();      

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

Employee employeeObj = new Employee(1, "Lokesh", "Gupta", "[email protected]");
 
Gson gson = new GsonBuilder()
        .setVersion(1.1)
        .setPrettyPrinting()
        .create();
 
System.out.println(gson.toJson(employeeObj));      

輸出:

{
  "id": 1,
  "firstName": "Lokesh",
  "lastName": "Gupta"
}      

我們将JSON字元串反序列化為版本号為Employee的對象。

String json = "{'id': 1001, "
                + "'firstName': 'Lokesh',"
                + "'lastName': 'Gupta',"
                + "'email': '[email protected]'}";
 
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]      

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

預設情況下,我們假設Java模型類和JSON将具有完全相同的字段名稱。

但有時情況并非如此,某些名稱有所不同。現在我們必須将json中的someName映射到Java類中的someOtherName。這是@SerializedName注解用到的地方。

@SerializedName注解訓示帶注解的成員變量應使用提供的名稱值作為其字段名稱序列化為JSON。此注解将覆寫可能一直在使用GsonBuilder類的任何FieldNamingPolicy,包括預設的字段命名政策。

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

注解包含屬性

  • value –序列化或反序列化時所需的字段名稱。
  • alternate–反序列化時字段的備用名稱。除了“值”屬性外,它還提供了更多可能的名稱。如果有多個字段比對一個屬性,則Gson将使用最後處理的那個。

讓我們以隻有四個字段的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", "[email protected]");
 
Gson gson = new GsonBuilder().setPrettyPrinting().create();  
 
System.out.println(gson.toJson(emp));      
{
  "id": 1001,
  "firstName": "Lokesh",
  "lastName": "Gupta",
  "emailId": "[email protected]"
}      

在将JSON反序列化為Java類的過程中映射不同的字段名稱:

Json:

{
  "id": 1001,
  "firstName": "Lokesh",
  "lastName": "Gupta",
  "email": "[email protected]",
  "emailAddress": "[email protected]"
}      

Main.java:

String json = "{'id': 1001,"
        + "'firstName': 'Lokesh',"
        + "'lastName': 'Gupta',"
        + "'email': '[email protected]',"
        + "'emailAddress': '[email protected]'}";
         
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 protected]]      

Gson允許我們從Java類中排除或忽略不希望包含在序列化和反序列化中的字段。

Gson支援許多内置機制,用于排除頂級類,字段和字段類型。

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

@Expose注釋在要顯式指定應進行序列化或反序列化的所有字段的程式設計方式中很有用。

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

  • serialize –如果為true,則在序列化時會在JSON中寫出帶有此注解的字段。
  • deserialize –如果為true,則從JSON反序列化帶有此注解的字段。
@Expose(serialize = false) 
private String lastName;
 
@Expose (serialize = false, deserialize = false) 
private String emailAddress;      

如果我們使用 new Gson() 建立Gson并執行toJson() 和 fromJson() 方法,則@Expose将不會對序列化和反序列化産生任何影響。要使用此批注,我們必須使用GsonBuilder類及其excludeFieldsWithoutExposeAnnotation()方法建立Gson執行個體。

Gson gson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .create();      

預設情況下,如果我們僅将字段标記為瞬時态,則Gson會将字段從序列化和反序列化中排除。

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

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

@Expose(serialize = false) 
private String lastName;
 
private transient String emailAddress;      

通過使用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();      

如果以上任何一種技術都不适合我們,那麼我們可以建立自己的政策。

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();      

對于簡單的用例,使用’Gson gson = new Gson();’ 标準配置就足夠了。 但是,如果打算自定義Gson的行為,則可以使用GsonBuilder自定義的配置來建立新的Gson執行個體。

GsonBuilder類提供一個.create()方法,該方法傳回一個Gson執行個體。

Gson gson = new GsonBuilder().create();       

預設情況下,Gson将建立緊湊的JSON字元串。這對于減少通過網絡傳輸的資料量非常有用。

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

Gson gson = new GsonBuilder()
        .setPrettyPrinting()
        .create();       

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

它有助于Gson執行個體将Java字段名稱正确轉換為所需的JSON字段名稱。

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

public class User 
{
    private int id;
    private String first_Name;
    private String lastName;
    private String _email;
}      

如何使用FieldNamingPolicy:

User user = new User(1, "Lokesh", "Gupta", "[email protected]");
         
Gson gson = new GsonBuilder()
                .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
                .setPrettyPrinting().create(); 
 
System.out.println(gson.toJson(user));      

以下示範每種命名政策下轉換的不同的名稱。

使用此命名政策字段名稱不變。這個是預設的政策:

{
  "id": 1,
  "first_Name": "Lokesh",
  "lastName": "Gupta",
  "_email": "[email protected]"
}      

Gson會将Java字段名稱從其駝峰大小寫形式修改為小寫的字段名稱,其中每個單詞都用破折号(-)分隔。

{
  "id": 1,
  "first_-name": "Lokesh",
  "last-name": "Gupta",
  "_email": "[email protected]"
}      

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

{
  "id": 1,
  "first_.name": "Lokesh",
  "last.name": "Gupta",
  "_email": "[email protected]"
}      

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

{
  "id": 1,
  "first__name": "Lokesh",
  "last_name": "Gupta",
  "_email": "[email protected]"
}      

Gson将確定序列化為JSON格式的Java字段名稱的第一個“字母”大寫:

{
  "Id": 1,
  "First_Name": "Lokesh",
  "LastName": "Gupta",
  "_Email": "[email protected]"
}      

Gson将確定在将Java字段名稱的第一個“字母”序列化為JSON格式時将其大寫,并且單詞之間将使用空格分隔:

{
  "Id": 1,
  "First_ Name": "Lokesh",
  "Last Name": "Gupta",
  "_Email": "[email protected]"
}      

預設情況下,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
}      

  • 對于序列化,如果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();       

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

如果JSON違反結構規則之一,它将抛出MalformedJsonException。如果我們将lenient設定為true,則它将忽視某些違規行為,并嘗試讀取格式不正确的JSON。

Gson gson = new GsonBuilder()
        .setLenient()
        .setPrettyPrinting().create();       

使用Gson JsonReader類,該類是基于拉式的流JSON解析器。它有助于将JSON作為令牌流讀取。

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

在流模式下,每個JSON資料都被視為一個單獨的令牌。

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

{
    "name":"Lokesh"
}      

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

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

我們可以使用它的簡單構造函數建立一個JsonReader執行個體,該執行個體接受java.io.Reader類型的輸入流。

String json = "{}";
JsonReader jsonReader = new JsonReader( new StringReader(json) );      

我們可以根據JSON流的來源使用以下閱讀器之一:

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

建立包含有效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()以遞歸地跳過該值的嵌套令牌,否則可能會發生沖突。

Gson JsonParser用于将Json資料解析為JsonElement的解析樹,進而解析為JsonObject。

JsonObject可用于使用JSON字元串中的相應鍵來通路值。

JsonParser類隻有一個預設構造函數,并且不需要任何參數或配置。

JsonParser parser = new JsonParser();      

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樹中解析了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()方法從中提取字段。

使用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': '[email protected]'}";
 
        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"
"[email protected]"      

我們可以使用Gson執行個體及其fromJson()方法來獲得相同的結果:

String json = "{'id': 1001, "
        + "'firstName': 'Lokesh',"
        + "'lastName': 'Gupta',"
        + "'email': '[email protected]'}";
 
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': '[email protected]'}";
 
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"));      

這是一個完整的示例,展示了如何疊代從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");
    }

}      

Gson在預設序列化和反序列化方面提供了非常出色的功能。

不過,我們可能會遇到預設和内置自定義選項無法解決我們問題的情況。在這種情況下,我們可以通過兩個接口JsonSerializer和JsonDeserializer使用自定義序列化和反序列化。

JsonSerializer.java:

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

為Json建立自定義序列化程式後,我們還需要通過GsonBuilder.registerTypeAdapter(Type,Object)注冊該序列化程式。

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

假設我們遇到一種情況,我們必須将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", "[email protected]", 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": "[email protected]",
  "active": 1
}      

定制反序列化器必須實作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()。

假設某些服務将日期字段分别分為天,月和年等部分分别傳回給我們。在JSON字元串中,它們可能有意義,但是在Java中,它們隻有作為單個java.time.LocalDate對象的一部分時才有意義。

employee.json:

{
  "id": 1,
  "firstName": "Lokesh",
  "lastName": "Gupta",
  "email": "[email protected]",
  "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對象:

public class Main 
{
    public static void main(String[] args) throws Exception 
    {
        String json = "{'id': 1001,"
                    + "'firstName': 'Lokesh',"
                    + "'lastName': 'Gupta',"
                    + "'email': '[email protected]', "
                    + "'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 protected], 
        dob=2019-08-11]