Gson 源码解读
Posted maplejaw_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gson 源码解读相关的知识,希望对你有一定的参考价值。
转载请注明本文出自maplejaw的博客(http://blog.csdn.net/maplejaw_)
开源库地址:https://github.com/google/gson
解读版本:2.7
Gson是一个可以用来将Java对象转换为JSON字符串的Java库。当然,它也可以把JSON字符串转换为等价的Java对象。网上已经有了不少可将Java对象转换成JSON的开源项目。但是,大多数都要求你在Java类中加入注解,如果你无法修改源码的话就比较坑爹了,此外大多数开源库并没有对泛型提供完全的支持。于是,Gson在这两个重要的设计目标下诞生了。Gson可以作用于任意的Java对象(包括接触不到源码的),与此同时还加入了完整的泛型支持。
基本用法
- 基本数据类型
// 序列化为json
Gson gson = new Gson();
gson.toJson(1); // ==> 1
gson.toJson("abcd"); // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values); // ==> [1]
// 反序列化为java object
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);
- 对象
public class User {
public String name="maplejaw";
public int age=18;
public User(){
//无参构造方法
}
}
// 序列化
User obj = new User();
Gson gson = new Gson();
String json = gson.toJson(obj); // ==> json is {"name":"maplejaw","age":18}
//反序列化
User obj2 = gson.fromJson(json, User.class);
- 泛型
Type type= new TypeToken<List<User>>(){}.getType();
List<User> list = gson.fromJson(json, type);
- 配置Gson
Gson gson=new GsonBuilder()
.setLenient() //设置宽松的容错性
.setPrettyPrinting() //设置漂亮的打印(打印出来的有缩进风格)
.setVersion(..) //设置当前版本号
...
.create();
Gson的基本用法如上所示,使用起来比较简便,一般情况下也已经够用了。需要注意的是,Java对象一定要有一个无参构造方法,这是Gson实例化对象的关键(自定义实例后面介绍)。此外,Java对象中并不要求有set/get方法。一般只要了解以上基本用法就能够应付绝大多数情况了,如果想深入了解一些高级用法,请继续往下阅读源码解读。
源码解读
Gson中的5个注解
@Expose
表示某个成员变量暴露于JSON序列化/反序列化。只需在GsonBuilder中配置excludeFieldsWithoutExposeAnnotation()
时才会生效。当配置过后,只有使用了@Expose
注解的成员变量才会参与序列化/反序列化工作。public class User { @Expose private String firstName;//参与序列化(JAVA对象转为JSON)/反序列化(JSON转为JAVA对象) @Expose(serialize = false) private String lastName;//参与反序列化 @Expose (serialize = false, deserialize = false) private String emailAddress; //不参与 private String password;//不参与 }
@SerializedName
表示某个成员变量序列化/反序列化的名字,无需在GsonBuilder中配置就能生效,甚至会覆盖掉FieldNamingPolicy
。public class MyClass { @SerializedName("name") //a => 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); //===== 输入的json如下 ===== {"name":"v1","name1":"v2","c":"v3"} //同理,以下的json数据都能成功反序列化为MyClass。 {"name":"v1","name1":"v2","c":"v3"} {"name":"v1","name2":"v2","c":"v3"} {"name":"v1","name3":"v2","c":"v3"}
这个注解有什么好处呢?众所周知,在Java中的变量命名规则须遵守驼峰原则,但是,如果后台使用的是php等其他语言,将导致命名规则不一致;又或者因为其他原因导致多条json只有一个字段不一致,总不能建立多个实体类吧?这时候这个注解就派上用场了。
@Since
表示某个成员变量从哪个版本开始生效,只在GsonBuilder中配置了setVersion()
时才会生效。public class User { private String firstName;//一直参与 private String lastName;//一直参与 @Since(1.0) private String emailAddress; //当前版本>=1.0时才会参与序列化/反序列化,否则忽略 @Since(1.0) private String password;//当前版本>=1.0时才会参与序列化/反序列化,否则忽略 @Since(1.1) private Address address;//当前版本>=1.1时才会参与序列化/反序列化,否则忽略 }
@Until
表示某个成员变量从哪个版本开始失效,只在GsonBuilder中配置了setVersion()
时才会生效。public class User { private String firstName;//一直参与 private String lastName;//一直参与 @Until(1.1) private String emailAddress;//当前版本<=1.1时参加序列化/反序列化 @Until(1.1) private String password;//当前版本<=1.1时参加序列化/反序列化 }
@JsonAdapter
表示在某一个成员变量或者类上使用TypeAdapter。至于TypeAdapter是什么东东,后面介绍。举个例子:
假如有个User类如此下:public class User { public final String firstName, lastName; private User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } }
准备编写一个UserJsonAdapter。
public class UserJsonAdapter extends TypeAdapter<User> { @Override public void write(JsonWriter out, User user) throws IOException { out.beginObject(); out.name("name"); out.value(user.firstName + " " + user.lastName); out.endObject(); } @Override public User read(JsonReader in) throws IOException { in.beginObject(); in.nextName(); String[] nameParts = in.nextString().split(" "); in.endObject(); return new User(nameParts[0], nameParts[1]); } }
将UserJsonAdapter应用到属性:此时,Gadget中的User,将会按照UserJsonAdapter来进行序列化/反序列化
private static final class Gadget { @JsonAdapter(UserJsonAdapter.class) public User user; }
将UserJsonAdapter应用到类:此时,在序列化/反序列User对象时,都会按照UserJsonAdapter来执行。
@JsonAdapter(UserJsonAdapter.class) public class User { public final String firstName, lastName; private User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } }
JsonReader/JsonWriter
在Gson中,Java对象与JSON字符串之间的转换是通过字符流来进行操作的。JsonReader继承于Reader用来读取字符,JsonWriter继承于Writer用来写入字符。
假如,现在有如下一段JSON数据用来表示一个用户列表。name
为名字,age
为年龄,geo
为定位的经纬度。如何使用JsonReader转为java对象?
首先查看一下json的结构,不难发现最外层是一个数组。于是,我们定义出如下readJsonStream
从Stream(流)中读取用户列表,读取完毕后,务必记得关闭流。
//从流中读取List<User>
public List<User> readJsonStream(InputStream in) throws IOException {
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
try {
return readUserArray(reader);//读取用户列表
} finally {
reader.close();//关闭流
}
}
//读取List<User>
public List<User> readUserArray(JsonReader reader) throws IOException {
List<User> users = new ArrayList<User>();
reader.beginArray();//开始读取数组
while (reader.hasNext()) {//是否还有下个元素
users.add(readUser(reader));//读取下个元素
}
reader.endArray();//结束读取数组
return users;
}
//读取User对象
public User readUser(JsonReader reader) throws IOException {
String name = null;
int age = -1;
List<Double> geo=null;
reader.beginObject();//开始读取对象
while (reader.hasNext()) {//是否还有下个元素
String name = reader.nextName();//读取下一个json属性名
//判断属性名是哪一个
if (name.equals("name")) {
name = reader.nextString();
} else if (name.equals("age")) {
age = reader.nextInt();
} else if (name.equals("geo")&& reader.peek() != JsonToken.NULL) {
geo = readDoublesArray(reader);
} else {
reader.skipValue();//忽略没有匹配到内容的值
}
}
reader.endObject();//结束读取对象
return new User(name, age,geo);
}
//读取经纬度
public List<Double> readDoublesArray(JsonReader reader) throws IOException {
List<Double> doubles = new ArrayList<Double>();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}
我们不难发现如下规律,每次读取数组或者对象之前,都必须调用beginObject()
或者beginArray()
,读完相应内容后,也必须调用endObject()
或者endArray()
。reader.hasNext()
用来判断是否还有下一个元素,然后调用nextName
来取下一个属性名,以及一系列的nextXXX
来取相应的值。
上面介绍的是将json字符串转换为java对象的用法,现在来看看如何使用JsonWriter来讲java对象转为json字符串。
//将List<User>写入流中
public void writeJsonStream(OutputStream out, List<User> users) throws IOException {
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
writer.setIndent(" ");//设置缩进风格(设置后写入的字符串保持缩进风格,如果没有设置,将会顶格打印)
writeUsersArray(writer, users);//写入List<User>
writer.close();
}
//写入List<User>
public void writeUsersArray(JsonWriter writer, List<User> users) throws IOException {
writer.beginArray();//开始写入数组
for (User user : users) {
writeUser(writer, user);
}
writer.endArray();//结束写入数组
}
//写入User
public void writeUser(JsonWriter writer, User user) throws IOException {
writer.beginObject();//开始写入对象
writer.name("name").value(user.getName());
writer.name("age").value(user.getAge());
if (user.getGeo() != null) {
writer.name("geo");
writeDoublesArray(writer, user.getGeo());
} else {
writer.name("geo").nullValue();
}
writer.endObject();//结束写入对象
}
public void writeDoublesArray(JsonWriter writer, List<Double> doubles) throws IOException {
writer.beginArray();
for (Double value : doubles) {
writer.value(value);
}
writer.endArray();
}
JsonWriter用来写入JSON字符串的规则和JsonWriter大相径庭,每次写入数组或者对象之前,都必须调用beginObject()
或者beginArray()
,写完相应内容后,也必须调用endObject()
或者endArray()
。name(xx)
用来写入名字,value(XX)
用来写入值。
接下来,深入浅出解析源码!stream包的结构如下:
枚举类JsonToken
的源码如下,主要用于表示JSON字符串中的名字/值的结构。
public enum JsonToken {
BEGIN_ARRAY,//JSON array开始
END_ARRAY,//JSON array结束
BEGIN_OBJECT,//JSON object开始
END_OBJECT,//JSON object结束
NAME,//JSON 属性名,JsonReader#nextName/JsonWriter#name
STRING,//JSON 字符串
NUMBER,//JSON 数字,代表java中double,long,int
BOOLEAN,//JSON 布尔值
NULL, //表示 null
END_DOCUMENT //表示JSON流的结尾
}
JsonScope是一个常量类,元素词法作用域。用来标识JsonReader/JsonWriter现在读/写到哪了。
final class JsonScope {
static final int EMPTY_ARRAY = 1;//没有元素的数组(相当于之前刚读了“[”),下一个元素一定不是逗号。
static final int NONEMPTY_ARRAY = 2;//非空数组(至少已经有一个元素),下一个元素不是逗号就是“]”
static final int EMPTY_OBJECT = 3;//空对象(刚读到“{”,一个name/value对都没有),下一个一定不是逗号。
static final int DANGLING_NAME = 4;//名字,下一个元素一定是值。
static final int NONEMPTY_OBJECT = 5;//非空对象(至少一个name/value对),下一个元素不是逗号就是“}”
static final int EMPTY_DOCUMENT = 6;//空文档,初识状态,啥也没读
static final int NONEMPTY_DOCUMENT = 7;//文档中有一个顶级的数组/对象
static final int CLOSED = 8;//文档已被关闭
}
JsonWriter
JsonWriter,用于将Java对象写为JSON字符串。使用前我们可以进行一些默认的配置:
//设置缩进符号,只要你设置了缩进符号,打印出来的字符串将会拥有缩进风格,非常漂亮
public final void setIndent(String indent)
//设置宽松的容错性(顶级值可以不是为object/array,数字可以为无穷)
public final void setLenient(boolean lenient)
//html转义
public final void setHtmlSafe(boolean htmlSafe)
//序列化空,默认true
public final void setSerializeNulls(boolean serializeNulls)
JsonWriter使用一个数组来保存当前的写入状态(就是标识写到哪了),JsonScope中已经介绍过了。
private int[] stack = new int[32];
private int stackSize = 0;
{
push(EMPTY_DOCUMENT);
}
注意stack并没有定死32的长度,当写满时将会扩大一倍。使用push
来保存当前写入状态,peek
查看当前状态。
//将当前状态保存栈顶
private void push(int newTop) {
if (stackSize == stack.length) {//如果满了就扩大一倍
int[] newStack = new int[stackSize * 2];
System.arraycopy(stack, 0, newStack, 0, stackSize);
stack = newStack;
}
stack[stackSize++] = newTop;
}
//查看栈顶的值
private int peek() {
if (stackSize == 0) {
throw new IllegalStateException("JsonWriter is closed.");
}
return stack[stackSize - 1];
}
在写一个对象之前,必须使用beginObject()
。一定很好奇beginObject()
做了什么,当时还不忙着看,先来看看怎么写入name/value的。
name(XX)
源码如下:
public JsonWriter name(String name) throws IOException {
if (name == null) {
throw new NullPointerException("name == null");
}
if (deferredName != null) {
throw new IllegalStateException();
}
if (stackSize == 0) {
throw new IllegalStateException("JsonWriter is closed.");
}
deferredName = name;//赋值给deferredName
return this;
}
看完源码不由觉得有点失望,只是赋值给了deferredName,其他什么事也没做。那么到底什么时候写入name的。这还得从写入value看起。
value(XX)
有很多重载函数。
我们只看value(String)
这种。
public JsonWriter value(String value) throws IOException {
if (value == null) {//如果空的话,写入空值
return nullValue();
}
writeDeferredName();//写入name。
beforeValue();//写入“:”(会对上次状态进行校验)
string(value);//写入value(会对特殊字符进行转码)
return this;
}
通过writeDeferredName
写入名字,beforeValue
写入:
,string
写入真正的值。当然writeDeferredName
也不是说直接写入name,而是先beforeName
进行状态校验,换行,替换状态,按需写入,
,然后使用string
写入name值。
private void writeDeferredName() throws IOException {
if (deferredName != null) {
beforeName();//校验等
string(deferredName);//写入名字
deferredName = null;
}
}
现在来看看beginObject
,如果该对象是name/value中的value,那么writeDeferredName用来写入name。open
写入{
以及更改栈顶状态。
public JsonWriter beginObject() throws IOException {
writeDeferredName();//写入name(如果有)
return open(EMPTY_OBJECT, "{"); //写入“{”
}
endObject
则是调用close
来写入}
,传入的EMPTY_OBJECT,EMPTY_OBJECT
用来比较是在哪种状态下进行关闭的。
public JsonWriter endObject() throws IOException {
return close(EMPTY_OBJECT, EMPTY_OBJECT, "}");
}
至于beginArray/endArray
的源码这里就不赘述了。
JsonReader
JsonReader,用于将JSON字符串转为Java对象。
JsonReader中的setLenient
的容错性那可是非常厉害。以下错误都能被忽略。
)]}'\\n
前缀- 多个顶级值
- 顶级值不是 object/array类型
- 数字类型为无穷数,或者不是个数字
- 一行的结尾存在//或者 #注释
- C语言风格的注释/…/
- name用了单引号或者没用引号
- string用了单引号或者没用引号
- 数组元素的分隔符用了;而不是,
- name和value不是用:分隔,而是用=或=>
- name/value对之间不是逗号分隔,而是;分隔
和JsonWriter一样,也使用一个数组stack来保存当前的读取到的字符的类型和状态。其中引入了一系列的PEEKED_XX
int常量来记录读取的字符类型。由于篇幅问题,JsonReader就不深入研究了,以下列出JsonReader中的核心方法。
fillBuffer
用来读取字符到buffer
数组中nextNonWhitespace
用来读取非空格/注释/换行等字符peek()
查看元素类型,对应于JsonToken中的值。doPeek()
内部使用了nextNonWhitespace
读取一个字符,然后设置当前的读取的字符类型。hasNext
object/array中是不是还有下一个元素nextName
读取下一个namenextString/nextInt/nextBoolean/nextLong/nextDouble/nextNull
用来读取下一个对应的值。skipValue
跳过下一个valuenextQuotedValue/nextUnquotedValue
用来读取下一个单引号/双引号没有引号括起来的name或者string valuebeginObject/endObject/beginArray/endArray
用来消费下一个对应类型的字符
Gson中的泛型
在了解Gson中的泛型前,我们来看两个类,$Gson$Types和$Gson$Preconditions。
$Gson$Types,专门用来处理泛型类型。核心源码如下:
//规范化类型
public static Type canonicalize(Type type) {
if (type instanceof Class) {//class
Class<?> c = (Class<?>) type;
return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
} else if (type instanceof ParameterizedType) {//泛型
ParameterizedType p = (ParameterizedType) type;
return new ParameterizedTypeImpl(p.getOwnerType(),
p.getRawType(), p.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {//数组类型
GenericArrayType g = (GenericArrayType) type;
return new GenericArrayTypeImpl(g.getGenericComponentType());
} else if (type instanceof WildcardType) {//通配符类型
WildcardType w = (WildcardType) type;
return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
} else {
// type is either serializable as-is or unsupported
return type;
}
}
//获取原始类型
public static Class<?> getRawType(Type type) {
if (type instanceof Class<?>) {
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
//泛型
ParameterizedType parameterizedType = (ParameterizedType) type;
Type rawType = parameterizedType.getRawType();
checkArgument(rawType instanceof Class);
return (Class<?>) rawType;
} else if (type instanceof GenericArrayType) {
//数组类型
Type componentType = ((GenericArrayType)type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
} else if (type instanceof TypeVariable) {
//类型变量的上边界是Object
return Object.class;
} else if (type instanceof WildcardType) {
//返回上边界
return getRawType(((WildcardType) type).getUpperBounds()[0]);
} else {
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <" + type + "> is of type " + className);
}
}
canonicalize这个方法中返回了一系列的XXImpl,其实只是实现了java.io.Serializable接口,重写了equal方法而已。其中ParameterizedType/GenericArrayType/WildcardType,熟悉泛型的应该不会陌生,这里就不赘述了。
$Gson$Preconditions,这个类用于条件校验,源码很是简洁。
public final class $Gson$Preconditions {
private $Gson$Preconditions() {
throw new UnsupportedOperationException();
}
public static <T> T checkNotNull(T obj) {//校验非空
if (obj == null) {
throw new NullPointerException();
}
return obj;
}
public static void checkArgument(boolean condition) {//校验是不是满足条件
if (!condition) {
throw new IllegalArgumentException();
}
}
}
现在回过来了解Gson中的泛型,Gson中用TypeToken来表示泛型。
源码如下:
public class TypeToken<T> {
final Class<? super T> rawType;//T的原始类型
final Type type; //T 的类型
final int hashCode;
protected TypeToken() {
//获取父类泛型的参数类型
this.type = getSuperclassTypeParameter(getClass());
//获取原始类型
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode();
}
public final Class<? super T> getRawType() {
return rawType;
}
public final Type getType() {
return type;
}
//..
//省略了部分源码
}
由于Java中只能通过getGenericSuperclass
获取父类泛型类型,所以TypeToken必须new出一个子类Type type= new TypeToken<List<User>>(){}.getType();
来使用。
getSuperclassTypeParameter
的源码如下:
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();//获取父类泛型类型
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
//获取泛型参数类型,即T的类型
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
JsonElement
JsonElement,一个抽象类,代表着JSON中的元素类型。可以表示JsonObject,JsonArray,JsonPrimitive,JsonNull。换言之,Gson中的JsonObject/JsonArray/JsonPrimitive/JsonNull继承于JsonElement。JsonElement也提供了一系列的getAsXXX
方法来获取元素。
我们着重看一下JsonPrimitive,JsonPrimitive代表着java中的基本数据类型。可以看出,通过构造方法进行赋值,然后通过getAsXX
取值。
public final class JsonPrimitive extends JsonElement {
//基本类型列表如下
private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,
float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,
Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
//值
private Object value;
public JsonPrimitive(Boolean bool) {
setValue(bool);
}
//赋值数字类型
public JsonPrimitive(Number number) {
setValue(number);
}
//赋值String
public JsonPrimitive(String string) {
setValue(string);
}
//赋值字符
public JsonPrimitive(Character c) {
setValue(c);
}
//赋值给value
void setValue(Object primitive) {
if (primitive instanceof Character) {
char c = ((Character) primitive).charValue();
this.value = String.valueOf(c);
} else {
$Gson$Preconditions.checkArgument(primitive instanceof Number
|| isPrimitiveOrString(primitive));
this.value = primitive;
}
}
//..
//省略了部分源码
}
Gson中的TypeAdapter
还记得介绍注解时提到的TypeAdapter吗?TypeAdapter是一个抽象类,可以用来自定义类型转换。源码如下。
public abstract class TypeAdapter<T> {
//抽象方法,写value(an array, object, string, number, boolean or null)
public abstract void write(JsonWriter out, T value) throws IOException;
//抽象方法,读value
public abstract T read(JsonReader in) throws IOException;
//包装方法,帮你处理了空值,你可以不用担心空值问题
public final TypeAdapter<T> nullSafe() {
return new TypeAdapter<T>() {
@Override public void write(JsonWriter out, T value) throws IOException {
if (value == null) {//如果为空,写入null
out.nullValue();
} else {
TypeAdapter.this.write(out, value);
}
}
@Override public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
return TypeAdapter.this.read(reader);
}
};
}
//..
//省略了部分源码
}
我们只需继承于TypeAdapter,实现相应方法就能实现自己的TypeAdapter,前面我们介绍了使用注解方法来使用TypeAdapter,现在来讲一下在GsonBuilder中如何使用。
Gson gson= new GsonBuilder()
.registerTypeAdapter(XX.class,new XXTypeAdapter())
.create();
在GsonBuilder中使用registerTypeAdapter配置后,就不需要使用相关注解了。那么问题来了,如果GsonBuilder和注解为同一个类配置了不同的TypeAdapter会发生什么状况?我可以很负责任的告诉你,注解的优先级是最高的。
此外,我们之前在编写UserJsonAdapter时没有处理空值情况,很容易会抛出异常,那怎么办?一种是自己处理空值情况,将代码改成如下形式。
public class UserJsonAdapter extends TypeAdapter<User> {
@Override
public void write(JsonWriter out, User user) throws IOException {
if (user == null) {//判断空值
out.nullValue();
retrun;
}
out.beginObject();
out.name("name");
out.value(user.firstName + " " + user.lastName);
out.endObject();
}
@Override
public User read(JsonReader in) throws IOException {
if (reader.peek() == JsonToken.NULL) {//判断空值
reader.nextNull();
return null;
}
in.beginObject();
in.nextName();
String[] nameParts = in.nextString().split(" ");
in.endObject();
return new User(nameParts[0], nameParts[1]);
}
}
第二种方法,使用nullSafe
:
Gson gson= new GsonBuilder()
.registerTypeAdapter(User.class,new UserJsonAdapter().nullSafe())
.create();
TypeAdapterFactory是一个创造TypeAdapter的工厂,用来创造一些相似类型的TypeAdapter。
public interface TypeAdapterFactory {
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
}
继承TypeAdapter,需要重写write
和read
相关方法,可是只想处理序列化和反序列化中的一种该怎么办?那么接下来就该介绍JsonSerializer
和JsonDeserializer
接口了。可以在@JsonAdapter
注解和registerTypeAdapter
中注册使用。
//序列化
public interface JsonSerializer<T> {
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
}
//反序列化
public interface JsonDeserializer<T> {
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)throws JsonParseException;
}
序列化策略
LongSerializationPolicy
枚举类,指定长整型的序列化类型,默认有DEFAULT,STRING两种类型,可继承它实现其他类型InstanceCreator 实例创造器
当反序列化时需要实例化对象,但是假如该对象没有默认构造方法怎么吧?那么就自定义自己的实例创造器。InstanceCreator一般配合ConstructorConstructor一起使用。public interface InstanceCreator<T> { public T createInstance(Type type); }
class UserInstanceCreator implements InstanceCreator<User> { public User createInstance(Type type) { return new User(null, -1); } }
FieldNamingStrategy
提供了一个自定义的字段命名机制public interface FieldNamingStrategy { public String translateName(Field f); }
FieldNamingPolicy
一个枚举类,实现了FieldNamingStrategy,提供了一些默认的字段命名机制,IDENTITY
:原始机制;UPPER_CAMEL_CASE
:首字母大写的驼峰映射;UPPER_CAMEL_CASE_WITH_SPACES
:用空格分隔的大写驼峰LOWER_CASE_WITH_UNDERSCORES
:下划线相连的小写映射;LOWER_CASE_WITH_DASHES
:虚线相连的小写映射。FieldAttributes
用来存取字段的属性:getName
获取字段名,getDeclaringClass
获取声明的类,getDeclaredType
获取字段的声明类型,getAnnotation
获取注解。ExclusionStrategy
一个用于定义排除策略的的接口。public interface ExclusionStrategy { //是否应该忽略该属性 public boolean shouldSkipField(FieldAttributes f); //是否应该忽略该类 public boolean shouldSkipClass(Class<?> clazz); }
其他
Excluder 排除器,主要用于根据策略和注解来判断哪些字段应该被忽略。
属性如下:private static final double IGNORE_VERSIONS = -1.0d; public static final Excluder DEFAULT = new Excluder(); //默认忽略版本号 private double version = IGNORE_VERSIONS; //默认以下修饰符的字段会被忽略 private int modifiers = Modifier.TRANSIENT | Modifier.STATIC; private boolean serializeInnerClasses = true;//序列化内部类 private boolean requireExpose;//需要Expose注解? //存放序列化排除策略 private List<ExclusionStrategy> serializationStrategies = Collections.emptyList(); //存放反序列化排除策略 private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList();
所有的方法如下:
Primitives 一个工具类,用于在原始类型和包装类型间转化。
wrap
包装,以上是关于Gson 源码解读的主要内容,如果未能解决你的问题,请参考以下文章