关于Json序列化的框架可以说比较多了,比如Spring默认的Jackson,国内互联网用的比较多的FastJson,本文则主要介绍一下Gson的简单使用姿势,并不会涉及到不同的json框架的性能对比
本文主要内容来源于官方教程: https://github.com/google/gson/blob/master/UserGuide.md
1. 依赖导入
首先我们借助maven来引入依赖包,按照自己的实际情况选择一个版本(简单的使用姿势与具体的版本并没有太大的关联性)
1 2
| <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId>
|
2. 基本的序列化与反序列化
一般来讲,我们通过Gson对象来实现Json的序列化与反序列化,如下是几个简单的序列化与反序列化的case
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Gson gson = new Gson(); gson.toJson(1); gson.toJson("abcd"); gson.toJson(new Long(10)); int[] values = { 1 }; gson.toJson(values);
int one = gson.fromJson("1", int.class); Integer one = gson.fromJson("1", Integer.class); Long one = gson.fromJson("1", Long.class); Boolean false = gson.fromJson("false", Boolean.class); String str = gson.fromJson("\"abc\"", String.class); String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);
|
上面的case中,主要就是借助gson.toJson
来输出Json字符串,借助gson.fromJson
返序列化得到对象
3. 对象序列化
对象的序列化与反序列化可以说是最常见的,在Gson的使用过程中,推荐的对象写法
- filed:private 修饰
- 不希望序列化的成员,添加
transient
修饰符
- 默认无参构造方法(可选,这里跟人推荐保留,不同于FastJson的必须存在)
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
| public static class BaseBean { private int age;
private String name;
private transient int code;
private String email;
public BaseBean() { }
@Override public String toString() { return "BaseBean{" + "age=" + age + ", name='" + name + '\'' + ", code=" + code + ", email='" + email + '\'' + '}'; } } @Test public void testObjGson() { BaseBean bean = new BaseBean(); bean.age = 10; bean.code = 20; bean.name = "一灰灰blog";
Gson gson = new Gson(); String str = gson.toJson(bean); System.out.println("json str: " + str);
BaseBean out = gson.fromJson(str, BaseBean.class); System.out.println("after deserialization: " + out); }
|
上面的使用姿势和前面并没有什么本质的区别,接下来看一下输出结果
1 2
| json str: {"age":10,"name":"一灰灰blog"} after deserialization: BaseBean{age=10, name='一灰灰blog', code=0, email='null'}
|
请注意:
- 输出json串时,null和
transient
修饰的成员不会输出到json串中
- 对象没有Get/Set方法,也依然可以反序列化(对象也没有继承自Serialize接口,当然我个人的观点是请继承Serialize接口)
如果我希望将null的成员,也可以输出到json串,可以如下操作
1 2 3
| Gson gsonWithNUll = new GsonBuilder().serializeNulls().create(); System.out.println("serialize with null: " + gsonWithNUll.toJson(bean));
|
输出结果如下
1
| serialize with null: {"age":10,"name":"一灰灰blog","email":null}
|
说明:如果希望扩展序列化方式,通过GsonBuilder来构建Gson对象是一个不错的选择
4. JsonObject与JsonArray
某些场景下我们可能并没有定义反序列化的数据对象,比如FastJson中的直接反序列化为JSONObject/JSONArray
,然后手动获取数据进行业务处理,这种场景下,gson可以如何支持呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Map map = new HashMap(); map.put("a", "hello world"); map.put(12, true); map.put("array", Arrays.asList("a", "c", "f", 12)); map.put("obj", Maps.newHashMap("k", "v"));
Gson gson = new Gson(); String str = gson.toJson(map);
JsonObject obj = JsonParser.parseString(str).getAsJsonObject(); String a = obj.get("a").getAsString(); boolean b = obj.get("12").getAsBoolean(); JsonArray ary = obj.get("array").getAsJsonArray(); JsonObject o = obj.get("obj").getAsJsonObject();
System.out.println("a:" + a + " b:" + b + " ary:" + ary + " o:" + o);
|
请注意,我们这里主要借助的是JsonParser.parseString
方法,输入参数可以是String也可以是流,返回的是JsonElement
对象,这个对象比较有意思,提供了一些基础的类型输出方法如
- getAsString: 返回String
- getAsInt: 返回int
- getAsJsonArray: 返回JsonArray(json数组)
- getAsJsonObject: 返回JsonObject (Json对象)
- …
5. 泛型序列化
以上属于常规的基本使用姿势,实际的工作中,关于泛型的序列化和反序列化可以说非常常见了,那么应该如何处理呢
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
| public static class ResWrapper<T> { private T data; private int code; private String msg; }
public static class User { private int age; private String name; }
@Test public void testGenri() { ResWrapper<User> wrapper = new ResWrapper<>(); wrapper.code = 0; wrapper.msg = "name";
User user = new User(); user.age = 18; user.name = "一灰灰";
wrapper.data = user;
Gson gson = new Gson(); String str = gson.toJson(wrapper);
Type type = new TypeToken<ResWrapper<User>>() {}.getType(); ResWrapper<User> out = gson.fromJson(str, type); System.out.println(out); }
|
上面的核心在于Type的生成: new TypeToken<ResWrapper<User>>() {}.getType();
6. 进阶
以上内容基本上可以覆盖日常业务开发中90%的场景,当然gson也支持一些更高级的功能
如filed name映射
@SerializedName("custom_naming")
1 2 3 4 5 6 7 8 9 10
| private class SomeObject { @SerializedName("custom_naming") private final String someField; private final String someOtherField;
public SomeObject(String a, String b) { this.someField = a; this.someOtherField = b; } }
|
如版本支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class VersionedClass { @Since(1.1) private final String newerField; @Since(1.0) private final String newField; private final String field;
public VersionedClass() { this.newerField = "newer"; this.newField = "new"; this.field = "old"; } }
VersionedClass versionedObject = new VersionedClass(); Gson gson = new GsonBuilder().setVersion(1.0).create(); String jsonOutput = gson.toJson(versionedObject); System.out.println(jsonOutput); System.out.println();
gson = new Gson(); jsonOutput = gson.toJson(versionedObject); System.out.println(jsonOutput);
|
自定义的类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapter(MyType.class, new DateTimeSerializer()); gson.registerTypeAdapter(MyType.class, new DateTimeDeserializer());
private class DateTimeSerializer implements JsonSerializer<DateTime> { public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } }
private class DateTimeDeserializer implements JsonDeserializer<DateTime> { public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()); } }
|
可视化的json输出
1 2
| Gson gson = new GsonBuilder().setPrettyPrinting().create(); String jsonOutput = gson.toJson(someObject);
|
II. 其他
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
3. 扫描关注
一灰灰blog