天天看點

java gson序列化_Java 中使用 Gson 反序列化 JSON 資料

好長時間沒寫 Java,發現序列化、反序列化一個 JSON 資料真不是個容易的事情(主要還是年紀大了,記不住)。于是記錄一下使用 Gson 反序列化的方法。文中涉及的代碼都可以在這個 gson-deserialization-example 中找到。

作者本身不懂 Java,本着不負責的态度寫下這些内容,大牛勿噴,想抄代碼的菜鳥請珍重。

本文基于轉換期間沒有異常情況讨論,實際情況請珍重。

初始化

我們先建立一個簡單的 TestMain.java 檔案,用來運作我們後續的測試方法。

TestMain.java1

2

3

4

5public class TestMain{

public static void main(String args[]){

// 運作測試方法

}

}

通過 javac TestMain.java 會生成 TestMain.class 檔案,之後就能通過 java TestMain 運作 class 檔案。

在目前的例子中我們 google 的 Gson( maven 位址) 庫來做序列化和反序列化。簡單起見,我們直接下載下傳 jar 包,放到 lib 目錄下。

因為我們使用了 gson.jar 是以指令會變成這樣:

javac -classpath lib/gson-2.8.0.jar TestMain.java

java -classpath .:lib/gson-2.8.0.jar TestMain

JsonParser

Object

假設我們有這樣一個簡單的 JSON 資料:

1

2

3

4

5

6

7

8

9

10

11

12

{

"name": "Hans Chan",

"age": 18,

"tags": [{

"id": 1,

"text": "JavaScript"

}, {

"id": 2,

"text": "Java"

}]

}

使用 JsonParser 足夠的簡單:

1

2JsonParser jsonParser = new JsonParser();

JsonElement userJsonElement = jsonParser.parse(json);

所有東西都是 抽象 的 JsonElement(api),如果要擷取具體的内容,就得轉換成 JsonObject 或 JsonArray 等類型,擷取方式也非常直覺 .get("key"):

1

2

3

4JsonObject userJsonObject = userJsonElement.getAsJsonObject();

String name = userJsonObject.get("name").getAsString();

int age = userJsonObject.get("age").getAsInt();

JsonArray userTagsJsonArray = userJsonObject.get("tags").getAsJsonArray();

Array

同樣的場景,如果輸入的 json 字元串不是 {} 而是 [],也可以通過上述方法擷取:

1

2

3

4

5

6String json = "[{},{}]"; // 每個 {} 都是一個 Sample JSON

JsonArray userJsonArray = jsonParser.parse(json).getAsJsonArray(); // 不是 getAsJsonObject

for (int i = 0; i < userJsonArray.size(); i++) {

JsonObject userJsonObject = userJsonArray.get(i).getAsJsonObject();

// ...

}

Serialization

JsonElement 的序列化很簡單,直接 .toString() 即可。

1String json = userJsonObject.toString(); // JsonObject

OO

這下子,寫 Java 的哥們就肯定會跳出來說 “這是什麼鬼,一點都不 OO”。的确上面的方式很 js,于是我們就要寫得像 Java 一點,先來兩個 class :

1

2

3

4

5

6

7

8

9

10

11private class Tag{

private int id;

private String text;

// 此處省略 Getter and Setter

}

private class User{

private String name;

private int age;

private List tags;

// 此處省略 Getter and Setter

}

Object

大家注意了,我要變形了!(敲黑闆)

1

2Gson gson = new Gson();

User user = gson.fromJson(json, User.class);

通過 Gson,String 被轉換成指定的 User.class,然後我們就可以愉快地操作這個執行個體了:

1

2

3

4

5List tags = user.getTags();

for (int i = 0; i < tags.size(); i++) {

Tag tag = tags.get(i);

System.out.println("tag " + tag.getId() + ": " + tag.getText());

}

Array

還是同樣的例子,如果是 [] 怎麼辦?我們當然期望是獲得一個 List 啦,但沒有 List.class 這個東西,怎麼破?沒關系,Gson 裡面還有個 TypeToken 是可以跟你幹這事的,我們隻需要這樣:

1

2

3

4

5

6// import com.google.common.reflect.TypeToken;

TypeToken typeToken = new TypeToken>() {};

// import java.lang.reflect.Type;

Type type = typeToken.getType();

List users = gson.fromJson(json, type);

還是可以愉快地玩耍的,不是麽 😂

Serialization

Class 要反序列化就還是要依賴回 Gson 提供的 toJson 方法:

1String json = gson.toJson(user); // User

GsonBuilder

很多時候,輸入的 json 總有那麼一點不盡人意,例如下面這個例子:

1

2

3

4

5

6

7

8

9

10

11

12{

"id": 3,

"name": "Hans Chan",

"registrationTime": "1999-09-19 18:10:22",

"data": {

"some": "complex data",

"we": {

"do-NOT": ["care", "about", "what", "inside"],

"BUT": "needed!"

}

}

}

id 是我們需要的資料,但序列化出去的時候不想顯示

registrationTime 可能不是一個我們想要的格式

data 可能是我們不是很關心結構,但又需要儲存裡面的内容

利用 GsonBuilder 和 Annotation 我們就可以實作上面兩個功能:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28private class BaseUser{

// import com.google.gson.annotations.Expose;

@Expose(serialize = false, deserialize = true)

private int id;

@Expose

private String name;

// import com.google.gson.annotations.SerializedName;

@SerializedName("registrationTime")

@Expose

private Date registration;

public int getId(){

return id;

}

public Date getRegistration(){

return registration;

}

}

private class CustomBUser extends BaseUser{

@Expose

private JsonElement data;

public JsonElement getData(){

return data;

}

}

registrationTime 的格式我們用 GsonBuilder 聲明:

1

2

3

4

5

6Gson deserializationGson = new GsonBuilder()

// 不導出實體中沒有用 @Expose 注解的屬性

.excludeFieldsWithoutExposeAnnotation()

// 時間格式

.setDateFormat("yyyy-MM-dd HH:mm:ss")

.create();

愉快地玩耍吧:

1

2

3CustomBUser cbu = deserializationGson.fromJson(json, CustomBUser.class);

System.out.println("id: " + cbu.getId());

System.out.println(cau.getData());

自定義序列化和反序列化

上面的例子中,data 是直接用一個 JsonElement 來處理的,如果有更加個性化的要求,那就需要自己寫序列化和反序列化方法了。這裡我們自己實作一個 CustomUserData 類,用來處理 data 資料,直接實作上面相同的功能:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34private static class CustomUserData{

private JsonElement ctx;

public CustomUserData(JsonElement ctx){

this.ctx = ctx;

}

public String toString(){

return this.ctx.toString();

}

}

private class CustomAUser extends BaseUser{

@Expose

private CustomUserData data;

public CustomUserData getData(){

return data;

}

}

// 自定義反序列化方法

private static class CustomUserDataDeserializeAdapter implements JsonDeserializer{

@Override

public CustomUserData deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)

throws JsonParseException{

// 這裡實作複雜的功能

return new CustomUserData(json);

}

}

// 自定義序列化方法

public static class CustomUserDataSerializeAdapter implements JsonSerializer{

@Override

public JsonElement serialize(CustomUserData src, Type typeOfSrc, JsonSerializationContext context){

// 這裡實作複雜的功能

return src.ctx;

}

}

通過 registerTypeAdapter 給 GsonBuilder 注冊上面的自定義序列化方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18Gson deserializationGson = new GsonBuilder()

.excludeFieldsWithoutExposeAnnotation()

.setDateFormat("yyyy-MM-dd HH:mm:ss")

.registerTypeAdapter(CustomUserData.class, new CustomUserDataDeserializeAdapter())

.create();

Gson serializationGson = new GsonBuilder()

.excludeFieldsWithoutExposeAnnotation()

.setDateFormat("yyyy/MM/dd HH:mm:ss")

.registerTypeAdapter(CustomUserData.class, new CustomUserDataSerializeAdapter())

.setPrettyPrinting()

.create();

System.out.println("---------- CustomAUser ----------");

CustomAUser cau = deserializationGson.fromJson(json, CustomAUser.class);

System.out.println("id: " + cau.getId());

// System.out.println(cau.getRegistration());

// System.out.println(cau.getData()); // .toString()

System.out.println(serializationGson.toJson(cau));