本文基于 Gson 官方用户指南整理而成。相对于其他 JSON 框架,Gson 的性能并不逊色,加上 Google 官方维护的背景,成为 Java/Android 项目中处理 JSON 的首选。以下是对官方文档的全面梳理和备忘。
Gson 是 Google 开发的 Java 库,用于将 Java 对象序列化为 JSON 表示,以及将 JSON 字符串反序列化为 Java 对象。
性能和可伸缩性#
以下数据来自桌面系统(dual opteron, 8GB RAM, 64-bit Ubuntu),可通过 PerformanceTest 复现:
- strings:超过 25MB 的字符串反序列化没有问题
- Large collections:序列化 140 万对象的集合,反序列化 87000 对象的集合
- Gson 1.4 将数组的反序列化限制从 80KB 提升到了 11MB
基础用法#
基本类型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // 序列化
Gson gson = new Gson();
gson.toJson(1); ==> prints 1
gson.toJson("abcd"); ==> prints "abcd"
gson.toJson(new Long(10)); ==> prints 10
int[] values = { 1 };
gson.toJson(values); ==> prints [1]
// 反序列化
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);
|
对象示例#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
// 序列化
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
==> json is {"value1":1,"value2":"abc"}
// 反序列化
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
==> obj2 is just like obj
|
- 推荐使用
private 字段 - 不需要注解来标记序列化字段,当前类及其所有父类的字段都会默认序列化
transient 字段会被自动忽略null 处理:- 序列化时,
null 字段会被跳过 - 反序列化时,JSON 中缺失的键对应的字段值会被设为
null
synthetic(合成)字段不会被序列化- 内部类、匿名类和局部类的外部类引用字段会被忽略,不会参与序列化和反序列化
嵌套类#
Gson 可以轻松序列化/反序列化静态嵌套类,但无法自动反序列化非静态内部类,因为其无参构造函数需要外部类引用,在反序列化时无法提供。
1
2
3
4
5
6
7
8
9
10
| // NOTE: 这个 class B 默认不会被 Gson 正确序列化
public class A {
public String a;
class B {
public String b;
public B() {
// No args constructor for B
}
}
}
|
Gson 无法反序列化 {"b":"abc"} 因为 class B 是内部类。两种解决方案:
- 将 B 定义为
static class B - 自定义 InstanceCreator:
1
2
3
4
5
6
7
8
9
10
| // 可行但不推荐
public class InstanceCreatorForB implements InstanceCreator<A.B> {
private final A a;
public InstanceCreatorForB(A a) {
this.a = a;
}
public A.B createInstance(Type type) {
return a.new B();
}
}
|
1
2
3
4
5
6
7
8
9
10
| Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
// 序列化
gson.toJson(ints); ==> prints [1,2,3,4,5]
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]
// 反序列化
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
|
Gson 也支持任意复杂元素类型的多维数组。
1
2
3
4
5
6
7
8
9
| Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);
// 序列化
String json = gson.toJson(ints); ==> json is [1,2,3,4,5]
// 反序列化
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
|
注意:Java 的泛型擦除使得反序列化时必须通过 TypeToken 指定具体泛型类型。
集合限制#
- 可以序列化任意类型的集合,但无法自动反序列化(无法确定元素数据类型)
- 反序列化时,集合必须是具体泛型化的集合
由于 Java 的类型擦除,直接对泛型对象进行序列化/反序列化会丢失类型信息:
1
2
3
4
5
6
7
8
| class Foo<T> {
T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // 可能无法正确序列化 foo.value
gson.fromJson(json, foo.getClass()); // 无法将 foo.value 反序列化为 Bar
|
通过 TypeToken 解决:
1
2
3
| Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);
|
混合类型集合#
对于 JSON 数组 ['hello', 5, {name: 'GREETINGS', source: 'guest'}]:
1
2
3
4
| Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));
|
序列化很简单,但反序列化需要额外操作。三种方法:
- 推荐:使用 Gson 的解析 API(JsonParser)逐个解析元素
- 为
Collection.class 注册类型适配器 - 使用
Collection<MyCollectionMemberType> 并注册适配器
使用 JsonParser 的示例:
1
2
3
4
5
6
| Gson gson = new Gson();
JsonParser parser = new JsonParser();
JsonArray array = parser.parse(json).getAsJsonArray();
String message = gson.fromJson(array.get(0), String.class);
int number = gson.fromJson(array.get(1), int.class);
Event event = gson.fromJson(array.get(2), Event.class);
|
内置类型支持#
Gson 内置了以下类型的序列化/反序列化:
java.net.URL — 匹配字符串 http://code.google.com/p/google-gson/java.net.URI — 匹配字符串 /p/google-gson/
Joda-Time 支持#
DateTime:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| private static class DateTimeTypeConverter
implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
@Override
public JsonElement serialize(DateTime src, Type srcType,
JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
@Override
public DateTime deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
try {
return new DateTime(json.getAsString());
} catch (IllegalArgumentException e) {
Date date = context.deserialize(json, Date.class);
return new DateTime(date);
}
}
}
|
Instant:
1
2
3
4
5
6
7
8
9
10
11
12
13
| private static class InstantTypeConverter
implements JsonSerializer<Instant>, JsonDeserializer<Instant> {
@Override
public JsonElement serialize(Instant src, Type srcType,
JsonSerializationContext context) {
return new JsonPrimitive(src.getMillis());
}
@Override
public Instant deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
return new Instant(json.getAsLong());
}
}
|
自定义序列化和反序列化#
Gson 通过 GsonBuilder 注册自定义的序列化器:
1
2
3
4
5
| GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter());
gson.registerTypeAdapter(MyType.class, new MySerializer());
gson.registerTypeAdapter(MyType.class, new MyDeserializer());
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());
|
registerTypeAdapter 会检查适配器是否实现了多个接口,并相应注册。
自定义序列化器#
1
2
3
4
5
6
| private class DateTimeSerializer implements JsonSerializer<DateTime> {
public JsonElement serialize(DateTime src, Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
}
|
自定义反序列化器#
1
2
3
4
5
6
| private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
public DateTime deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return new DateTime(json.getAsJsonPrimitive().getAsString());
}
}
|
泛型类型的统一处理#
如果有一个 Id<T> 类,不同泛型参数的序列化方式相同,可以注册一个处理器统一处理所有 Id 类型:
1
2
| // Gson 支持注册单一处理器处理所有同 raw type 的泛型,
// 也支持为特定泛型注册独立处理器
|
实例构造器(Instance Creator)#
反序列化时,Gson 需要创建对象实例。如果类没有无参构造方法,就需要提供 InstanceCreator。
1
2
3
4
5
| private class MoneyInstanceCreator implements InstanceCreator<Money> {
public Money createInstance(Type type) {
return new Money("1000000", CurrencyCode.USD);
}
}
|
参数化类型的实例构造#
1
2
3
4
5
6
7
8
| class MyList<T> extends ArrayList<T> { }
class MyListInstanceCreator implements InstanceCreator<MyList<?>> {
@SuppressWarnings("unchecked")
public MyList<?> createInstance(Type type) {
return new MyList();
}
}
|
对于需要在构造时获取参数化类型信息的场景:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class Id<T> {
private final Class<T> classOfId;
private final long value;
public Id(Class<T> classOfId, long value) {
this.classOfId = classOfId;
this.value = value;
}
}
class IdInstanceCreator implements InstanceCreator<Id<?>> {
public Id<?> createInstance(Type type) {
Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();
Type idType = typeParameters[0];
return Id.get((Class)idType, 0L);
}
}
|
格式化输出#
默认 Gson 输出紧凑格式,无空白字符。需要美化输出时:
1
2
| Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);
|
NULL 对象处理#
默认情况下,Gson 忽略 null 字段。如需序列化 null 值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| Gson gson = new GsonBuilder().serializeNulls().create();
public class Foo {
private final String s;
private final int i;
public Foo() {
this(null, 5);
}
public Foo(String s, int i) {
this.s = s;
this.i = i;
}
}
Foo foo = new Foo();
String json = gson.toJson(foo);
System.out.println(json); // {"s":null,"i":5}
|
版本支持#
通过 @Since 注解支持同一对象的多版本控制:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @Since(1.1) private final String newerField;
@Since(1.0) private final String newField;
private final String field;
VersionedClass versionedObject = new VersionedClass();
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
// {"newField":"new","field":"old"}
gson = new Gson();
jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
// {"newerField":"newer","newField":"new","field":"old"}
|
字段排除#
Java Modifier 排除#
默认排除 transient 和 static 字段。如需只排除 static:
1
2
3
| Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC)
.create();
|
支持多种修饰符组合:
1
2
3
| Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
.create();
|
@Expose 注解#
通过 @Expose 注解标记需要暴露的字段,未标记的字段被排除:
1
2
3
| Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
|
自定义排除策略#
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
| @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Foo {
// Field tag only annotation
}
public class MyExclusionStrategy implements ExclusionStrategy {
private final Class<?> typeToSkip;
private MyExclusionStrategy(Class<?> typeToSkip) {
this.typeToSkip = typeToSkip;
}
public boolean shouldSkipClass(Class<?> clazz) {
return (clazz == typeToSkip);
}
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(Foo.class) != null;
}
}
Gson gson = new GsonBuilder()
.setExclusionStrategies(new MyExclusionStrategy(String.class))
.serializeNulls()
.create();
|
字段命名#
Gson 支持预定义的字段命名策略和 @SerializedName 注解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| 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;
}
}
SomeObject someObject = new SomeObject("first", "second");
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.create();
String jsonRepresentation = gson.toJson(someObject);
System.out.println(jsonRepresentation);
// {"custom_naming":"first","SomeOtherField":"second"}
|
参考资料#