簡介
基本類型示例
// 創(chuàng)建Gson對象
Gson gson = new Gson();
// 反序列化
int a1 = gson.fromJson("1", int.class); // ==> 1
Integer a2 = gson.fromJson("1", Integer.class); // ==> 1
Long a3 = gson.fromJson("1", Long.class); // ==> 1
Boolean a4 = gson.fromJson("false", Boolean.class); // ==> false
String a5 = gson.fromJson("\"abc\"", String.class); // ==> "abc"
String[] a6 = gson.fromJson("[\"abc\", \"def\"]", String[].class); // ==> {"abc", "def"}
// 序列化
String s1 = gson.toJson(1); // ==> "1"
String s2 = gson.toJson("abcd"); // ==> "\"abcd\""
String s3 = gson.toJson(10L); // ==> "10"
int[] values = {1};
String s4 = gson.toJson(values); // ==> "[1]"
對象示例
代碼
class A {
private String name = "Tim";
private int age = 18;
private boolean isStudent = true;
private String sex = "male";
private String[] girlFriends = { "Alice", "Amy", "Mary" };
private B Alice = new B(); // 盡管沒有這句,內(nèi)部類也會有實例欧穴,但是沒有這句,就不會序列化或反序列化。
class B {
private String name = "Alice";
private int age = 17;
private boolean isStudent = true;
private String sex = "female";
private String boyFriend = "Tim";
private B() {}
}
}
Gson gson = new Gson();
// 序列化
A a1 = new A();
String json = gson.toJson(a1);
// 反序列化
A a2 = gson.fromJson(json, A.class);
一些細(xì)節(jié)
- 最好使用
private
訪問控制匆瓜。 - 默認(rèn)情況下锐锣,所有字段都會被序列化或反序列化技即。
- 如果字段被標(biāo)記為
@transient
著洼,則不會被序列化或反序列化。 - 能正確地處理
null
的情況:- 序列化:
null
字段被跳過而叼。 - 反序列化:缺失的字段會被設(shè)置為
null
身笤。
- 序列化:
- 如果字段是
synthetic
的,則不會進(jìn)行序列化或反序列化葵陵。 - 在字段前加上
@SerializedName("name")
可以改變序列化的名字液荸。
泛型示例
下面例子展示了如何從java數(shù)組轉(zhuǎn)換成List<String>
,直接使用List<String>.class
是不可行的脱篙,必須使用TypeToken
娇钱。
Gson gson = new Gson();
String jsonArray = "[\"Android\",\"Java\",\"PHP\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());
注:TypeToken
的構(gòu)造方法是protected
修飾的,所以上面才會寫成new TypeToken<List<String>>() {}.getType()
而不是new TypeToken<List<String>>().getType()
涡尘,先繼承后使用忍弛。
Gson 可以序列化或反序列化以下泛型類响迂,但是提供類型信息時需要像上述那樣提供TypeToken
考抄。
public class Result<T> {
public int code;
public String message;
public T data;
}
流式序列化與反序列化
流式反序列化
自動方式
直接將 Java 的Reader
當(dāng)做String
來使用。
Gson.toJson(Object);
Gson.fromJson(Reader,Class);
Gson.fromJson(String,Class);
Gson.fromJson(Reader,Type);
Gson.fromJson(String,Type);
手動方式
通過JsonReader
來逐個反序列化蔗彤。
String json = "{\"name\":\"Tim\",\"age\":\"24\"}";
User user = new User();
JsonReader reader = new JsonReader(new StringReader(json));
reader.beginObject(); // throws IOException
while (reader.hasNext()) {
String s = reader.nextName();
switch (s) {
case "name":
user.name = reader.nextString();
break;
case "age":
user.age = reader.nextInt(); //自動轉(zhuǎn)換
break;
case "email":
user.email = reader.nextString();
break;
}
}
reader.endObject(); // throws IOException
System.out.println(user.name); // Tim
System.out.println(user.age); // 24
System.out.println(user.email); // Tim@example.com
流式序列化
自動方式
Gson gson = new Gson();
User user = new User("Tim",24,"Tim@example.com");
gson.toJson(user,System.out); // 寫到控制臺
手動方式
JsonWriter writer = new JsonWriter(new OutputStreamWriter(System.out));
writer.beginObject() // throws IOException
.name("name").value("Tim")
.name("age").value(24)
.name("email").nullValue() //演示null
.endObject(); // throws IOException
writer.flush(); // throws IOException
//{"name":"Tim","age":24,"email":null}
注:除了beginObject()
川梅、endObject()
還有beginArray()
和endArray()
,兩者可以相互嵌套然遏,注意配對即可贫途。beginArray()
后不可以調(diào)用name()
,同樣beginObject()
后在調(diào)用value()
之前必須要調(diào)用name()
待侵。
GsonBuilder
Gson 在默認(rèn)情況下是不序列化值為null
的字段的丢早,可以通過GsonBuilder
改變配置。
public class User {
public String name;
public int age;
public String email;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
Gson gson = new GsonBuilder()
//序列化null
.serializeNulls()
// 設(shè)置日期時間格式,另有2個重載方法
// 在序列化和反序化時均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化內(nèi)部類
.disableInnerClassSerialization()
//生成不可執(zhí)行的Json
.generateNonExecutableJson()
//禁止轉(zhuǎn)義html標(biāo)簽
.disableHtmlEscaping()
//格式化輸出
.setPrettyPrinting()
.create();
User user = new User("Tim", 24);
System.out.println(gson.toJson(user)); //{"name":"Tim","age":24,"email":null}
普通過濾字段
通過@Expose
注解標(biāo)注要序列化或反序列化的字段怨酝,只在使用GsonBuilder
傀缩,且設(shè)置了excludeFieldsWithoutExposeAnnotation()
時生效
@Expose //序列化和反序列化都都生效
@Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效
@Expose(deserialize = true,serialize = false) //反序列化時生效
@Expose(deserialize = false,serialize = true) //序列化時生效
@Expose(deserialize = false,serialize = false) // 和不寫一樣
public class Category {
@Expose public int id;
@Expose public String name;
@Expose public List<Category> children;
//不需要序列化,所以不加 @Expose 注解,
//等價于 @Expose(deserialize = false,serialize = false)
public Category parent;
}
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
gson.toJson(category);
基于版本過濾字段
使用@Since
和@Until
來標(biāo)記版本农猬,在使用GsonBuilder
且設(shè)置setVersion()
時生效赡艰。
class SinceUntilSample {
@Since(4)
public String since;
@Until(5)
public String until;
}
SinceUntilSample sinceUntilSample = new SinceUntilSample();
sinceUntilSample.since = "since";
sinceUntilSample.until = "until";
Gson gson = new GsonBuilder().setVersion(version).create();
System.out.println(gson.toJson(sinceUntilSample));
注:當(dāng)一個字段被同時注解時,需兩者同時滿足條件斤葱。
基于訪問控制符過濾字段
只有在調(diào)用了GsonBuilder
的excludeFieldsWithModifiers()
時生效慷垮。
class ModifierSample {
final String finalField = "final";
static String staticField = "static";
public String publicField = "public";
protected String protectedField = "protected";
String defaultField = "default";
private String privateField = "private";
}
ModifierSample modifierSample = new ModifierSample();
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
.create();
System.out.println(gson.toJson(modifierSample));
// 結(jié)果:{"publicField":"public","protectedField":"protected","defaultField":"default"}
基于策略過濾字段
Gson gson = new GsonBuilder()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
// 這里作判斷,決定要不要排除該字段,return true為排除
if ("finalField".equals(f.getName())) return true; //按字段名排除
Expose expose = f.getAnnotation(Expose.class);
if (expose != null && expose.deserialize() == false) return true; //按注解排除
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
// 直接排除某個類 揍堕,return true為排除
return (clazz == int.class || clazz == Integer.class);
}
})
.create();
Java對象與Json字段映射規(guī)則
@SerializedName注解
可以在字段前加上@SerializedName
注解來定義序列化或反序列化的名字料身。
// value為默認(rèn)名字
// alternate為可選名字
@SerializedName(value = "name", alternate = {"name1", "name2"})
若同時出現(xiàn)多個匹配的名字,即 Json 字符串中包含"name"
衩茸,"name1"
惯驼,"name3"
時,以 Json 最后出現(xiàn)的為準(zhǔn)递瑰。
通過FieldNamingPolicy
對于emailAddress
字段祟牲,選用不同的FieldNamingPolicy
,會映射不同的 Json 字段抖部。
FieldNamingPolicy | 結(jié)果(僅輸出emailAddress字段) |
---|---|
IDENTITY(默認(rèn)與java字段名一致) | {"emailAddress":"Tim@example.com"} |
LOWER_CASE_WITH_DASHES | {"email-address":"Tim@example.com"} |
LOWER_CASE_WITH_UNDERSCORES | {"email_address":"Tim@example.com"} |
UPPER_CAMEL_CASE | {"EmailAddress":"Tim@example.com"} |
UPPER_CAMEL_CASE_WITH_SPACES | {"Email Address":"Tim@example.com"} |
A a = new A();
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)
.create();
String json = gson.toJson(a);
通過FieldNamingStrategy
通過實現(xiàn)通過FieldNamingStrategy
接口的方式:
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new FieldNamingStrategy() {
@Override
public String translateName(Field f) {
//實現(xiàn)自己的規(guī)則
return null;
}
})
.create();
注意: @SerializedName
注解擁有最高優(yōu)先級说贝,在加有@SerializedName
注解的字段上FieldNamingStrategy
不生效!
定制性最高的方式:使用TypeAdapter
TypeAdapter
是用于用于接管某種類型的序列化和反序列化過程慎颗。包含兩個主要方法write(JsonWriter,T)
和read(JsonReader)
其它的方法都是final
方法并最終調(diào)用這兩個抽象方法乡恕。
注冊TypeAdapter
本例中只接管User
類的序列化和反序列化,也可以只接管Integer
類型等俯萎。
User user = new User("Tim", 24);
user.emailAddress = "Tim@example.com";
Gson gson = new GsonBuilder()
//定制User類型的序列化或反序列化傲宜,通過使用UserTypeAdapter(繼承了TypeAdapter)。
.registerTypeAdapter(User.class, new UserTypeAdapter())
.create();
System.out.println(gson.toJson(user));
定義UserTypeAdapter
public class UserTypeAdapter extends TypeAdapter<User> {
@Override
public void write(JsonWriter out, User value) throws IOException {
out.beginObject();
out.name("name").value(value.name);
out.name("age").value(value.age);
out.name("email").value(value.email);
out.endObject();
}
@Override
public User read(JsonReader in) throws IOException {
User user = new User();
in.beginObject();
while (in.hasNext()) {
switch (in.nextName()) {
case "name":
user.name = in.nextString();
break;
case "age":
user.age = in.nextInt();
break;
case "email":
case "email_address":
case "emailAddress":
user.email = in.nextString();
break;
}
}
in.endObject();
return user;
}
}
JsonSerializer 與 JsonDeserializer
注冊TypeAdapter
必須要同時定制序列化和反序列化夫啊,但是可以使用JsonSerializer
或JsonDeserializer
來定制其中之一函卒。
Gson gson = new GsonBuilder()
.registerTypeAdapter(Integer.class, new JsonDeserializer<Integer>() {
@Override
public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return json.getAsInt();
} catch (NumberFormatException e) {
return -1;
}
}
})
.create();
System.out.println(gson.toJson(100)); //結(jié)果:100
System.out.println(gson.fromJson("\"\"", Integer.class)); //結(jié)果-1
// 數(shù)字轉(zhuǎn)字符串
JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() {
@Override
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(String.valueOf(src));
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(Integer.class, numberJsonSerializer)
.registerTypeAdapter(Long.class, numberJsonSerializer)
.registerTypeAdapter(Float.class, numberJsonSerializer)
.registerTypeAdapter(Double.class, numberJsonSerializer)
.create();
System.out.println(gson.toJson(100.0f));//結(jié)果:"100.0"
TypeAdapter 與 JsonSerializer、JsonDeserializer 比較
TypeAdapter | JsonSerializer撇眯、JsonDeserializer | |
---|---|---|
引入版本 | 2.0 | 1.x |
Stream API | 支持 | 不支持报嵌,需要提前生成JsonElement |
內(nèi)存占用 | 小 | 比TypeAdapter大 |
效率 | 高 | 比TypeAdapter低 |
作用范圍 | 序列化 和 反序列化 | 序列化 或 反序列化 |
registerTypeAdapter 與 registerTypeHierarchyAdapter 的區(qū)別
區(qū)別
registerTypeAdapter | registerTypeHierarchyAdapter | |
---|---|---|
支持泛型 | 是 | 否 |
支持繼承 | 否 | 是 |
使用registerTypeAdapter的泛型例子
注:如果一個被序列化的對象本身就帶有泛型,且注冊了相應(yīng)的TypeAdapter
熊榛,那么必須調(diào)用Gson.toJson(Object,Type)
锚国,明確告訴 Gson 對象的類型。
Type type = new TypeToken<List<User>>() {}.getType();
TypeAdapter typeAdapter = new TypeAdapter<List<User>>() {
//略
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(type, typeAdapter)
.create();
List<User> list = new ArrayList<>();
list.add(new User("a",11));
list.add(new User("b",22));
//注意玄坦,多了個type參數(shù)
String result = gson.toJson(list, type);
使用registerTypeHierarchyAdapter的泛型例子
缺失血筑。
// 數(shù)字轉(zhuǎn)字符串
JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() {
@Override
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(String.valueOf(src));
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(Integer.class, numberJsonSerializer)
.registerTypeAdapter(Long.class, numberJsonSerializer)
.registerTypeAdapter(Float.class, numberJsonSerializer)
.registerTypeAdapter(Double.class, numberJsonSerializer)
.create();
System.out.println(gson.toJson(100.0f));//結(jié)果:"100.0"
注:上面的Integer
、Long
、Float
豺总、Double
必須分別注冊梆砸,不能使用這4個類的父類取代,除非使用registerTypeHierarchyAdapter
而非registerTypeAdapter
园欣。
TypeAdapterFactory
TypeAdapterFactory
帖世,見名知意,用于創(chuàng)建TypeAdapter
的工廠類沸枯,通過對比Type
日矫,確定有沒有對應(yīng)的TypeAdapter
,沒有就返回null
绑榴,與GsonBuilder.registerTypeAdapterFactory
配合使用哪轿。
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
// 泛型方法
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return null;
}
})
.create();
@JsonAdapter注解
JsonAdapter
接收一個參數(shù),且必須是TypeAdpater
翔怎,JsonSerializer
或JsonDeserializer
這三個其中之一窃诉。使用了JsonAdapter
就不用每次使用GsonBuilder
去注冊UserTypeAdapter
了。
注意:JsonAdapter
的優(yōu)先級比GsonBuilder.registerTypeAdapter()
的優(yōu)先級更高赤套。
@JsonAdapter(UserTypeAdapter.class) //加在類上
public class User {
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String name;
public int age;
@SerializedName(value = "emailAddress")
public String email;
}