Gson是一个能将java对象序列化为json串,或者将json串反序列化为java对象的类库。
在Gson中,最常用的两个对象方法就是toJson()和fromJson()方法,下面是一个对象使用例子:
class Example {
private int s = 1;
private String str = "abc";
private transient int s2 = 3;
Example () {
}
}
// Serialization
Example obj = new Example ();
Gson gson = new Gson();
String json = gson.toJson(obj);
// ==> json {"s":1,"str":"abc"}
// Deserialization
Example obj2 = gson.fromJson(json, Example .class);
数组例子:
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"ac", "e", "gh"};
// 序列化
gson.toJson(ints); // [1,2,3,4,5]
gson.toJson(strings); //["ac", "e", "gh"]
// 反序列化
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
注意点:
- 序列化的时候,如果对象的其中一个变量为空,那么就不会输出这个变量。
- 一般来说,类中将这些要序列化的变量声明为私有的(private)是最合适的。
- 默认情况下,变量都会被序列化。
- 如果一个变量被标记为transient,那么默认它是不会被序列化和反序列化的。
- 如果一个变量声明为synthetic,那它也不会被序列化以及反序列化。
- 内部类,匿名类和本地类那些相对于外部类中的变量不会被序列化或反序列化。
如下:
public class A {
public String a;
class B {
public String b;
public B() {
}
}
}
Gson不能序列化上面的类B。但是Gson可以很容易的序列化静态嵌套类。又例如将{"b":"abc"}
反序列化为类B的对象是不可能的。除了将类B声明为静态的方法之外,还有一种方法,就是为B写一个自定义的实例构造器
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();
}
}
但这种方法官方不推荐。
集合的序列化和反序列化:Gson可以序列化任意对象的集合,但是不能反序列化。因为我们不知道结果对象的类型。所以此时需采用一个TypeToken类来协助反序列化。
Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);
String json = gson.toJson(ints); // json [1,2,3,4,5]
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
同样的,在对泛型进行序列化和反序列化时,我们也需要这个TypeToken类。因为java中的类型擦除机制,Gson在利用反射原理(obj.getClass())序列化和反序列化一个泛型类对象时,不知道对象的具体类型。例如:
class Foo<T> {
T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly
gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar
在上面的序列化过程中,Gson通过反射机制得到的是一个原生的Foo.class,而不是Foo<Bar>
。所以通过TypeToken类解决此类问题:
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);
任意类型对象集合的序列化和反序列化:Gson可以轻松利用toJson(collection)
序列化一个集合对象。但是反序列化时就会有问题。因为Gson不知道应该怎么映射数据和类型。例如:['hello',5,{name:'GREETINGS',source:'guest'}]
这个json数组。
Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));
通过下面这行语句就能序列化collection对象,但反序列化就会出现困难。
gson.toJson(collection);
此时又三种方法来反序列化:
- 使用Gson的Parser API来对json串进行解析。例如:
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);
2.为Collection.class注册一个类型适配器,查找每一个数组成员,将其映射到合适的对象。
3. 为MyCollectionMemberType注册一个类型适配器,然后使用Collection<MyCollectionMemberType>
fromJson()
来解析。
自定义序列器和反序列器:也许有些时候默认的表示并不能满足你的需求,这时候你可以自定义序列器和反序列器。例如:
private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new DateTime(json.getAsJsonPrimitive().getAsString());
}
}
然后需要将其注册:
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType.class, new DateTimeDeserializer());
Null对象支持:之前说过Gson默认是不输出null的变量的。但我们可以通过
Gson gson = new GsonBuilder().serializeNulls().create();
创建一个Gson实例,用它去序列化带null变量的对象时,就能将其输出。
版本支持:我们可以通过使用@Since注解维持同一对象的多个版本。此注解可以用于类,变量,方法。用法如下:
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(someObject);
System.out.println(jsonOutput);
System.out.println();
gson = new Gson();
jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
输出:
{"newField":"new","field":"old"}
{"newerField":"newer","newField":"new","field":"old"}
序列化和反序列化时去除变量:Gson提供了很多这种去除变量的机制。
- java Modifier Exclusion
默认情况下,如果一个变量被声明为transient或者是static,那么这个变量在对象序列化时就会被忽略。但如果你只想去除声明为static的变量,可以这么做:
import java.lang.reflect.Modifier;
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC)
.create();
这样的话,被声明为transient的变量就会被序列化了。
2. Gson’s @Expose
通过
new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
创建Gson实例,就会序列化类中所有被标记了@Expose的变量,去除没有标记的变量。
3. 用户定义去除策略
关键是实现ExclusionStrategy借口。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Foo {
// Field tag only annotation
}
public class SampleObjectForTest {
@Foo private final int annotatedField;
private final String stringField;
private final long longField;
private final Class<?> clazzField;
public SampleObjectForTest() {
annotatedField = 5;
stringField = "someDefaultValue";
longField = 1234;
}
}
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;
}
}
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.setExclusionStrategies(new MyExclusionStrategy(String.class))
.serializeNulls()
.create();
SampleObjectForTest src = new SampleObjectForTest();
String json = gson.toJson(src);
System.out.println(json);
}
输出:
{"longField":1234}
JSON变量名支持:可以同在在要序列化的类中变量前加@SerializedName注解,来制定序列化后的json串的显示名称。如下所示:
public class MyClass {
@SerializedName("name") String a;
@SerializedName(value="name1", alternate={"name2", "name3"}) String b;
String c;
public MyClass(String a, String b, String c) {
this.a = a;
this.b = b;
this.c = c;
}
}
MyClass target = new MyClass("v1", "v2", "v3");
Gson gson = new Gson();
String json = gson.toJson(target);
System.out.println(json);
===== OUTPUT =====
{"name":"v1","name1":"v2","c":"v3"}
MyClass target = gson.fromJson("{'name1':'v1'}", MyClass.class);
assertEquals("v1", target.b);
target = gson.fromJson("{'name2':'v2'}", MyClass.class);
assertEquals("v2", target.b);
target = gson.fromJson("{'name3':'v3'}", MyClass.class);
assertEquals("v3", target.b);
alter属性里是一个String数组,在反序列化时,无论json串中出现哪一个,都可以被反序列化。另外,Gson还有一个FieldNamingPolicy枚举类型。可以在创建Gson实例时传入,定义命名规则。
具体可查看:
https://github.com/google/gson/blob/master/UserGuide.md