@
- 一、簡介
- 二、依賴
- 三、基本用法
- 四、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'
三、基本用法
1、創建Gson實例
使用Gson的第一步是創建一個Gson對象,創建愛你Gson對象有兩種方式:
- 使用 new Gson()
- 創建GsonBuilder實例,使用 create() 方法
1.1、new Gson()
示例如下:
Gson gson = new Gson();
1.2、GsonBuilder.build()
示例如下:
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對象。
Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
Gson gson = new Gson();
String jsonString = gson.toJson(emp);
System.out.println(jsonString);
運行結果:
3、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);
運行結果:
4、漂亮地輸出
默認情況下,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));
運行結果:
5、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.1、數組類型成員變量
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.2、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);
運行結果:
6、JSON <---->Set
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);
運行結果:
7、Null值處理
Gson中實現的默認行為是忽略空對象字段。
例如,如果在Employee對象中未指定電子郵件(即email為null),則電子郵件將不會被序列化JSON輸出。Gson會忽略null字段,因為此行為允許使用更緊湊的JSON輸出格式。
7.1、如何在序列化時允許空值
要配置Gson實例以輸出null,我們必須使用GsonBuilder對象的serializeNulls()。
Gson gson = new GsonBuilder()
.serializeNulls()
.create();
8、版本支持
應用程序隨着時間變化,模型類也隨之變化。有時候更新/刪除字段可能會被打斷。
所有這些更改都可以使用@Since注釋進行標記,以跟蹤模型類,在這些系統使用反序列化JSON數據進行交換時,與其他系統的應用程序交互不會中斷。
8.1、@Since注解
在Gson中,可以使用@Since注釋維護同一對象的多個版本。可以在類,字段以及將來的方法中使用此注釋。它采用單個參數– ignoreVersionsAfter。
當我們為Gson實例配置版本號“ M.N”時,所有標記有版本大於M.N的類字段都將被忽略。例如,如果我們將Gson配置為版本號“ 1.2”,則所有版本號更高的字段(例如1.3、1.4…)都將被忽略。
@Since(1.2)
private String email;
8.2、如何使用@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.3、創建具備版本支持的Gson實例
要創建使用過@Since注解的Gson實例,需要使用GsonBuilder.setVersion()方法:
Gson gson = new GsonBuilder()
.setVersion(1.1)
.create();
8.4、實例
8.4.1、 具備版本支持的序列化
讓序列號以上的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.2、具備版本支持的反序列化
我們將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]
9、更改Java對象和JSON的字段名映射
在此Gson @SerializedName示例中,演示在序列化和反序列化過程中更改json和java對象之間的字段名稱。
9.1、@SerializedName
默認情況下,我們假設Java模型類和JSON將具有完全相同的字段名稱。
但有時情況並非如此,某些名稱有所不同。現在我們必須將json中的someName映射到Java類中的someOtherName。這是@SerializedName注解用到的地方。
@SerializedName注解指示帶注解的成員變量應使用提供的名稱值作為其字段名稱序列化為JSON。此注解將覆蓋可能一直在使用GsonBuilder類的任何FieldNamingPolicy,包括默認的字段命名策略。
請注意,在此注解中指定的值必須是有效的JSON字段名稱。
注解包含屬性
- value –序列化或反序列化時所需的字段名稱。
- alternate–反序列化時字段的備用名稱。除了“值”屬性外,它還提供了更多可能的名稱。如果有多個字段匹配一個屬性,則Gson將使用最后處理的那個。
9.2、序列化期時更改字段名稱
讓我們以只有四個字段的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.3、反序列化時更改字段名稱
在將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]
10、排除或忽略字段
Gson允許我們從Java類中排除或忽略不希望包含在序列化和反序列化中的字段。
Gson支持許多內置機制,用於排除頂級類,字段和字段類型。
10.1、@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.2、創建Gson實例
如果我們使用 new Gson() 創建Gson並執行toJson() 和 fromJson() 方法,則@Expose將不會對序列化和反序列化產生任何影響。要使用此批注,我們必須使用GsonBuilder類及其excludeFieldsWithoutExposeAnnotation()方法創建Gson實例。
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
10.2、用修飾符排除字段
10.2.1、transient 字段
默認情況下,如果我們僅將字段標記為瞬時態,則Gson會將字段從序列化和反序列化中排除。
請記住,它無法阻止單向轉換。它同時阻止了兩者。
transient 具有與@Expose相同的效果(serialize = false,deserialize = false)。
@Expose(serialize = false)
private String lastName;
private transient String emailAddress;
10.2.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.3、排除策略
如果以上任何一種技術都不適合我們,那么我們可以創建自己的策略。
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();
四、GsonBuilder
對於簡單的用例,使用'Gson gson = new Gson();' 標准配置就足夠了。 但是,如果打算自定義Gson的行為,則可以使用GsonBuilder自定義的配置來創建新的Gson實例。
GsonBuilder類提供一個.create()方法,該方法返回一個Gson實例。
Gson gson = new GsonBuilder().create();
1、GsonBuilder.setPrettyPrinting()–漂亮地打印JSON
默認情況下,Gson將創建緊湊的JSON字符串。這對於減少通過網絡傳輸的數據量非常有用。
但是,這種緊湊的JSON對開發人員進行開發/調試應用程序時不友好。使用漂亮的打印來格式化JSON輸出:
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
2、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.1、FieldNamingPolicy.IDENTITY
使用此命名策略字段名稱不變。這個是默認的策略:
{
"id": 1,
"first_Name": "Lokesh",
"lastName": "Gupta",
"_email": "admin@howtodoinjava.com"
}
2.2、FieldNamingPolicy.LOWER_CASE_WITH_DASHES
Gson會將Java字段名稱從其駝峰大小寫形式修改為小寫的字段名稱,其中每個單詞都用破折號(-)分隔。
{
"id": 1,
"first_-name": "Lokesh",
"last-name": "Gupta",
"_email": "admin@howtodoinjava.com"
}
2.3、FieldNamingPolicy.LOWER_CASE_WITH_DOTS
Gson會將Java字段名稱從其駝峰大小寫形式修改為小寫的字段名稱,其中每個單詞都用點(.)分隔:
{
"id": 1,
"first_.name": "Lokesh",
"last.name": "Gupta",
"_email": "admin@howtodoinjava.com"
}
2.4、FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
Gson會將Java字段名稱從其駝峰大小寫形式修改為小寫的字段名稱,其中每個單詞都用下划線(_)分隔。
{
"id": 1,
"first__name": "Lokesh",
"last_name": "Gupta",
"_email": "admin@howtodoinjava.com"
}
2.5、 FieldNamingPolicy.UPPER_CAMEL_CASE
Gson將確保序列化為JSON格式的Java字段名稱的第一個“字母”大寫:
{
"Id": 1,
"First_Name": "Lokesh",
"LastName": "Gupta",
"_Email": "admin@howtodoinjava.com"
}
2.6、FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES
Gson將確保在將Java字段名稱的第一個“字母”序列化為JSON格式時將其大寫,並且單詞之間將使用空格分隔:
{
"Id": 1,
"First_ Name": "Lokesh",
"Last Name": "Gupta",
"_Email": "admin@howtodoinjava.com"
}
3、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
}
4、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();
5、GsonBuilder.setLenient()——寬松的JSON語法規則
在反序列化期間,Gson使用了一個寬松的JsonReader類。這意味着它僅接受兼容的JSON輸入。
如果JSON違反結構規則之一,它將拋出MalformedJsonException。如果我們將lenient設置為true,則它將忽視某些違規行為,並嘗試讀取格式不正確的JSON。
Gson gson = new GsonBuilder()
.setLenient()
.setPrettyPrinting().create();
五、JsonReader
使用Gson JsonReader類,該類是基於拉式的流JSON解析器。它有助於將JSON作為令牌流讀取。
1、JsonReader
- JsonReader是流式JSON解析器,也是pull parser的示例。pull parser解析JSON令牌並將其推送到事件處理程序中。
- 它有助於讀取JSON(RFC 7159)編碼值作為令牌流。
- 它讀取字面值(字符串,數字,布爾值和null)以及對象和數組的開始和結束定界符。
- 令牌以深度優先順序遍歷,與JSON文檔中出現的順序相同。
2、Tokens
在流模式下,每個JSON數據都被視為一個單獨的令牌。
當我們使用JsonReader對其進行處理時,每個令牌將被順序處理。例如,
{
"name":"Lokesh"
}
在使用JsonReader進行解析時,以上JSON將生成4個令牌:
- Token 1 = {
- Token 2 = name
- Token 3 = Lokesh
- Token 4 = }
3、如何創建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
4、讀取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()以遞歸地跳過該值的嵌套令牌,否則可能會發生沖突。
六、JsonParser
Gson JsonParser用於將Json數據解析為JsonElement的解析樹,從而解析為JsonObject。
JsonObject可用於使用JSON字符串中的相應鍵來訪問值。
1、創建JsonParser
JsonParser類只有一個默認構造函數,並且不需要任何參數或配置。
JsonParser parser = new JsonParser();
2、轉化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。
3、 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()方法從中提取字段。
4、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"
5、使用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"));
6、迭代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");
}
}
七、自定義序列化和反序列化
Gson在默認序列化和反序列化方面提供了非常出色的功能。
不過,我們可能會遇到默認和內置自定義選項無法解決我們問題的情況。在這種情況下,我們可以通過兩個接口JsonSerializer和JsonDeserializer使用自定義序列化和反序列化。
1、自定義序列化
1.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.2、自定義序列化示例
假設我們遇到一種情況,我們必須將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、自定義反序列化
2.1、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.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