正確熟練的使用Gson這個開源庫能夠有效的提高開發(fā)的效率,它可以快捷的將json串轉(zhuǎn)化成Map<>,List<>或?qū)嶓w類,并支持反向操作
基本操作
// 序列化
String string = new Gson().toJson(user);
// 反序列化
User user = new Gson().fromeJson(string, User.class);
泛型的反序列化
// 序列化
String string = new Gson().toJson(userList);
// 反序列化
List<User> userList = new Gson().
fromeJson(string, new TypeToken<List<User>>(){}.getType());
TypeToken的源碼,可以對Java的泛型有更深刻的理解
復(fù)雜嵌套json串需要注意的問題
有些json串的嵌套很復(fù)雜,對象中某個字段為列表,列表中又有多個對象。在處理這種json串的時候要注意的是,分步操作,每一步操作后打印json串看一下
// 錯誤的json串格式,沒有雙引號
[{rec_id=797, type=4, data=杭州, remark=}]
// 正確的json串格式是有雙引號的,這樣才能保證被正確的解析
[{"rec_id":"797","type":"4","data":"杭州","remark":""}]
// 實際上如果上面的remark字段不為空,這兩種都可以被解析
// 但一旦有字段為空,沒有雙引號的那種就會拋出異常
在提取json串中的某一個對象的時候,若想單獨(dú)轉(zhuǎn)換成一個json串,應(yīng)該使用下面的方式
Map map = gson.fromJson(json, Map.class);
// 這種寫法是錯誤的,轉(zhuǎn)換完會是上面那種錯誤的json格式
String newjson = map.get("data").toString();
// 這種轉(zhuǎn)換方式才是正確的,以為通過map取得的也是一個對象
// 需要反序列化一次才能得到j(luò)son串,而不是直接toString()
String newjson = gson.toJson(map.get("data"));
變量名的對應(yīng)
很多情況下Java中的成員變量是通過駝峰式命名的,例如userName,passWord。而json的串可能是通過數(shù)據(jù)庫生成,數(shù)據(jù)庫中字段的命名方式為user_name,pass_word。這兩種命名方式在某些開源框架中是可以實現(xiàn)相互轉(zhuǎn)換的,雖然Gson不支持自動轉(zhuǎn)換,但可以通過下面的方式來映射Java中的成員變量名和json串中的key
@SerializedName("user_name")
private String userName;
如果Java的成員變量沒有對應(yīng)的json串中的key,則這個變量會被賦值為null,所以在成員變量的類型定義的時候,應(yīng)避免使用基本數(shù)據(jù)類型,而使用對應(yīng)的包裝器類型去替代
控制變量是否序列化
和對應(yīng)變量名的方法差不多,也是通過注解的方式來控制的,一個是@Expose注解,還有一個是@Since注解
-
@Expose注解有兩個變量:
serialize和deserialize,默認(rèn)值都是truepublic class User { @Expose private String userName; @Expose(serialize = false) private int age; @Expose(serialize = false, deserialize = false) private boolean admin; }這時序列化只會輸出userName字段,反序列化只會給userName和age字段賦值
需要注意的是,要想使@Expose這個注解生效,需要使用如下方法來構(gòu)建Gson對象Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation().create(); -
@Since注解主要用于進(jìn)行版本的控制
public class User { @Since(1.0) private String userName; @Since(1.1) private int age; @Since(1.1) private boolean admin; } Gson gson = new GsonBuilder().setVersion(1.0).create();在構(gòu)建Gson對象的時候使用GsonBuilder的方式,指定一個版本號,成員變量的版本號高于指定的版本號的時候,在轉(zhuǎn)換的時候?qū)缓雎?,例如上述例子,只有userName字段會被序列化和反序列化
重寫適配器
當(dāng)一個json串的字段的值為"",且這個字段對應(yīng)的成員變量的類型為int,由于空字符串無法轉(zhuǎn)化成int類型,所以就會報錯,這個時候多數(shù)情況下我們是希望其轉(zhuǎn)化成0的,或者是某一個默認(rèn)值,所以我們可以通過重寫適配器的方式,來達(dá)到我們想要達(dá)到的效果,僅以重寫int類型的適配器為例
public class IntegerDefaultAdapter
implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
@Override
public Integer deserialize(JsonElement json,
Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
// 此處可自定義規(guī)則
if (json.getAsString().equals("") ||
json.getAsString().equals("null")) {
return 0;
}
} catch (Exception ignore) {
// catch error
}
try {
return json.getAsInt();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
@Override
public JsonElement serialize(Integer src, Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src);
}
}
// 構(gòu)造Gson對象的方式
Gson gson = new GsonBuilder()
.registerTypeAdapter(Integer.class, new IntegerDefaultAdapter())
.create();
如果要寫其他類型的適配器,只需要更改上面的Integer為對應(yīng)的類型即可