简介
- GitHub地址:Gson
- API文档:Gson API
基本类型示例
// 创建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(); // 尽管没有这句,内部类也会有实例,但是没有这句,就不会序列化或反序列化。
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);
一些细节
- 最好使用
private
访问控制。 - 默认情况下,所有字段都会被序列化或反序列化。
- 如果字段被标记为
@transient
,则不会被序列化或反序列化。 - 能正确地处理
null
的情况:- 序列化:
null
字段被跳过。 - 反序列化:缺失的字段会被设置为
null
。
- 序列化:
- 如果字段是
synthetic
的,则不会进行序列化或反序列化。 - 在字段前加上
@SerializedName("name")
可以改变序列化的名字。
泛型示例
下面例子展示了如何从java数组转换成List
,直接使用List
是不可行的,必须使用TypeToken
。
Gson gson = new Gson();
String jsonArray = "[\"Android\",\"Java\",\"PHP\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
List stringList = gson.fromJson(jsonArray, new TypeToken>() {}.getType());
注:TypeToken
的构造方法是protected
修饰的,所以上面才会写成new TypeToken
而不是>() {}.getType()
new TypeToken
,先继承后使用。>().getType()
Gson 可以序列化或反序列化以下泛型类,但是提供类型信息时需要像上述那样提供TypeToken
。
public class Result {
public int code;
public String message;
public T data;
}
流式序列化与反序列化
流式反序列化
自动方式
直接将 Java 的Reader
当做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(); //自动转换
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); // [email protected]
流式序列化
自动方式
Gson gson = new Gson();
User user = new User("Tim",24,"[email protected]");
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()
后不可以调用name()
,同样beginObject()
后在调用value()
之前必须要调用name()
。
GsonBuilder
Gson 在默认情况下是不序列化值为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()
// 设置日期时间格式,另有2个重载方法
// 在序列化和反序化时均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化内部类
.disableInnerClassSerialization()
//生成不可执行的Json
.generateNonExecutableJson()
//禁止转义html标签
.disableHtmlEscaping()
//格式化输出
.setPrettyPrinting()
.create();
User user = new User("Tim", 24);
System.out.println(gson.toJson(user)); //{"name":"Tim","age":24,"email":null}
普通过滤字段
通过@Expose
注解标注要序列化或反序列化的字段,只在使用GsonBuilder
,且设置了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 children;
//不需要序列化,所以不加 @Expose 注解,
//等价于 @Expose(deserialize = false,serialize = false)
public Category parent;
}
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
gson.toJson(category);
基于版本过滤字段
使用@Since
和@Until
来标记版本,在使用GsonBuilder
且设置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));
注:当一个字段被同时注解时,需两者同时满足条件。
基于访问控制符过滤字段
只有在调用了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));
// 结果:{"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字段映射规则
@SerializedName注解
可以在字段前加上@SerializedName
注解来定义序列化或反序列化的名字。
// value为默认名字
// alternate为可选名字
@SerializedName(value = "name", alternate = {"name1", "name2"})
若同时出现多个匹配的名字,即 Json 字符串中包含"name"
,"name1"
,"name3"
时,以 Json 最后出现的为准。
通过FieldNamingPolicy
对于emailAddress
字段,选用不同的FieldNamingPolicy
,会映射不同的 Json 字段。
FieldNamingPolicy | 结果(仅输出emailAddress字段) |
---|---|
IDENTITY(默认与java字段名一致) | {"emailAddress":"[email protected]"} |
LOWER_CASE_WITH_DASHES | {"email-address":"[email protected]"} |
LOWER_CASE_WITH_UNDERSCORES | {"email_address":"[email protected]"} |
UPPER_CAMEL_CASE | {"EmailAddress":"[email protected]"} |
UPPER_CAMEL_CASE_WITH_SPACES | {"Email Address":"[email protected]"} |
A a = new A();
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)
.create();
String json = gson.toJson(a);
通过FieldNamingStrategy
通过实现通过FieldNamingStrategy
接口的方式:
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new FieldNamingStrategy() {
@Override
public String translateName(Field f) {
//实现自己的规则
return null;
}
})
.create();
注意: @SerializedName
注解拥有最高优先级,在加有@SerializedName
注解的字段上FieldNamingStrategy
不生效!
定制性最高的方式:使用TypeAdapter
TypeAdapter
是用于用于接管某种类型的序列化和反序列化过程。包含两个主要方法write(JsonWriter,T)
和read(JsonReader)
其它的方法都是final
方法并最终调用这两个抽象方法。
注册TypeAdapter
本例中只接管User
类的序列化和反序列化,也可以只接管Integer
类型等。
User user = new User("Tim", 24);
user.emailAddress = "[email protected]";
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 {
@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() {
@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)); //结果:100
System.out.println(gson.fromJson("\"\"", Integer.class)); //结果-1
// 数字转字符串
JsonSerializer numberJsonSerializer = new JsonSerializer() {
@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));//结果:"100.0"
TypeAdapter 与 JsonSerializer、JsonDeserializer 比较
TypeAdapter | JsonSerializer、JsonDeserializer | |
---|---|---|
引入版本 | 2.0 | 1.x |
Stream API | 支持 | 不支持,需要提前生成JsonElement |
内存占用 | 小 | 比TypeAdapter大 |
效率 | 高 | 比TypeAdapter低 |
作用范围 | 序列化 和 反序列化 | 序列化 或 反序列化 |
registerTypeAdapter 与 registerTypeHierarchyAdapter 的区别
区别
registerTypeAdapter | registerTypeHierarchyAdapter | |
---|---|---|
支持泛型 | 是 | 否 |
支持继承 | 否 | 是 |
使用registerTypeAdapter的泛型例子
注:如果一个被序列化的对象本身就带有泛型,且注册了相应的TypeAdapter
,那么必须调用Gson.toJson(Object,Type)
,明确告诉 Gson 对象的类型。
Type type = new TypeToken>() {}.getType();
TypeAdapter typeAdapter = new TypeAdapter>() {
//略
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(type, typeAdapter)
.create();
List list = new ArrayList<>();
list.add(new User("a",11));
list.add(new User("b",22));
//注意,多了个type参数
String result = gson.toJson(list, type);
使用registerTypeHierarchyAdapter的泛型例子
缺失。
// 数字转字符串
JsonSerializer numberJsonSerializer = new JsonSerializer() {
@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));//结果:"100.0"
注:上面的Integer
、Long
、Float
、Double
必须分别注册,不能使用这4个类的父类取代,除非使用registerTypeHierarchyAdapter
而非registerTypeAdapter
。
TypeAdapterFactory
TypeAdapterFactory
,见名知意,用于创建TypeAdapter
的工厂类,通过对比Type
,确定有没有对应的TypeAdapter
,没有就返回null
,与GsonBuilder.registerTypeAdapterFactory
配合使用。
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
// 泛型方法
@Override
public TypeAdapter create(Gson gson, TypeToken type) {
return null;
}
})
.create();
@JsonAdapter注解
JsonAdapter
接收一个参数,且必须是TypeAdpater
,JsonSerializer
或JsonDeserializer
这三个其中之一。使用了JsonAdapter
就不用每次使用GsonBuilder
去注册UserTypeAdapter
了。
注意:JsonAdapter
的优先级比GsonBuilder.registerTypeAdapter()
的优先级更高。
@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;
}