JSON (官网) 是一种文本形式的数据交换格式,它比XML更轻量、比二进制容易阅读和编写,调式也更加方便。其重要性不言而喻。解析和生成的方式很多,Java中最常用的类库有:JSON-Java、Gson、Jackson、FastJson等。
项目中使用了Gson,然而现在发现Gson差点被自己玩坏,所以决定好好学习一下~
Gson 基本用法
Gson 提供了两个方法 fromJson()
和 toJson()
方法直接用于解析和生成Json。前者实现反序列化,后者实现序列化。
基本数据类型解析
1 | Gson gson = new Gson(); |
基本数据类型生成
1 | Gson gson = new Gson(); |
POJO类的生成与解析
1 | public class User{ |
生成Json:1
2
3Gson gson = new Gson();
User user = new User("怪盗kidou",24);
String jsonObject = gson.toJson(user); // {"name":"怪盗kidou","age":24}
解析Json:1
2
3Gson gson = new Gson();
String jsonString = "{\"name\":\"怪盗kidou\",\"age\":24}";
User user = gson.fromJson(jsonString, User.class);
属性重命名
之前我们认为Gson对于服务器json数据的解析,属性名称需要与json中的key保持一致,一一对应。但是我们经常会遇到一些不和谐的情况。。。
@SerializedName注解使用
我们期望的json数据1
{"name":"leo","age":28,"emailAddress":"leo@example.com"}
服务端返回的json数据1
{"name":"leo","age":28,"email_address":leo@example.com}
谷歌的大神,怎么可能不考虑这个问题,我们来看一下如何处理,我们只需要将POJO中属性变成1
2@SerializedName("email_address")
public String emailAddress;
哦了,重命名的问题搞定~如果接口重用,后端的开发人员也更换了,来了一个偷懒的人。。。出现了下面的数据1
{"name":"leo","age":28,"emailAddress":"leo@example.com"}
1 | {"name":"leo","age":28,"email_address":leo@example.com} |
1 | {"name":"leo","age":28,"email":leo@example.com} |
我们如何处理?
为POJO字段提供属性备选名
SerializedName注解提供了两个属性,上面用到了其中一个,另外还有一个属性alternate(2.4版本以上),接收一个String数组。1
2"emailAddress", alternate = {"email", "email_address"}) (value =
public String emailAddress;
当上面的三个属性(email_address、email、emailAddress)出现任意一个时都可以得到正确的结果。
Gson泛型使用
Gson 为我们提供了 TypeToken
来实现对泛型的支持。
基本类型数据解析
1 | Gson gson = new Gson(); |
POJO的泛型数据解析
泛型的引入可以减少很多无关的代码,我们现在后台的数据接口数据主要有下面两类:1
2
3
4{
message : {"code":0,"message":"操作成功"},
"data":{}
}
1 | { |
我们真正需要的是 data 所包含的数据,message 中的数据我们只需要统一处理一次。如果我们不定义泛型那么我们就需要这样定义POJO。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class UserBean{
private MessageBean message;
private User data;
public MessageBean getMessage() {
return message;
}
public static class MessageBean {
/**
* code : 0
* message : 操作成功
*/
private int code;
private String message;
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
}
定义成泛型,就会简洁很多1
2
3
4public class Result<T>{
private MessageBean message;
private T data;
}
然后我们只需编写data字段所对应的POJO即可,专注于我们的业务逻辑。
解析数据的写法:1
2
3Type userType = new TypeToken<Result<User>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);
User user = userResult.data;
或1
2
3Type userListType = new TypeToken<Result<List<User>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType);
List<User> users = userListResult.data;
Gson 流操作
Gson 的流操作是通过stream包下的JsonReader类和JsonWriter来实现的。
Gson 流反序列化
1 | String json = "{\"name\":\"leo\",\"age\":\"28\"}"; |
fromJson()方法实际上就是通过JsonReader来进行数据解析的,不信? 去看源码喽~1
2
3
4
5
6
7
8public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
Gson 流序列化
序列化和反序列化始终是成对出现的,咱们这也不能让它落单不是。。。1
2
3
4
5
6
7JsonWriter writer = new JsonWriter(new OutputStreamWriter(System.out));
writer.beginObject() // throws IOException
.name("name").value("leo")
.name("age").value(28)
.name("email").nullValue() //演示null
.endObject(); // throws IOException
writer.flush(); // throws IOException
类似的,toJson() 方法自然是通过JsonWriter实现序列化1
2
3
4
5public String toJson(Object src, Type typeOfSrc) {
StringWriter writer = new StringWriter();
toJson(src, typeOfSrc, writer);
return writer.toString();
}
author @ygwang