http://blog.csdn.net/lk_blog/article/details/7685169
Gson是一个可以用来将Java对象转换为JSON字符串的Java库。当然,它也可以把JSON字符串转换为等价的Java对象。网上已经有了不少可将Java对象转换成JSON的开源项目。但是,大多数都要求你在Java类中加入注解,如果你无法修改源码的话就比较坑爹了,此外大多数开源库并没有对泛型提供完全的支持。于是,Gson在这两个重要的设计目标下诞生了。Gson可以作用于任意的Java对象(包括接触不到源码的),与此同时还加入了完整的泛型支持。
基本用法
Gson gson = new Gson();
gson.toJson(1 );
gson.toJson("abcd" );
gson.toJson(new Long(10 ));
int [] values = { 1 };
gson.toJson(values);
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
User obj2 = gson.fromJson(json, User.class);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Type type= new TypeToken>(){}.getType();
List list = gson.fromJson(json, type);
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;
@Expose (serialize = false )
private String lastName;
@Expose (serialize = false , deserialize = false )
private String emailAddress;
private String password;
}
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
@SerializedName 表示某个成员变量序列化/反序列化的名字,无需在GsonBuilder中配置就能生效,甚至会覆盖掉FieldNamingPolicy
。
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
当使用了该注解后,此时序列化/反序列化的情况如下:
MyClass target = new MyClass("v1" , "v2" , "v3" );
Gson gson = new Gson();
String json = gson.toJson(target);
{"name" :"v1" ,"name1" :"v2" ,"c" :"v3" }
{"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;
@Since (1.0 ) private String password;
@Since (1.1 ) private Address address;
}
@Until 表示某个成员变量从哪个版本开始失效,只在GsonBuilder中配置了setVersion()
时才会生效。
public class User {
private String firstName;
private String lastName;
@Until (1.1 ) private String emailAddress;
@Until (1.1 ) private String password;
}
@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 ]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
将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(流)中读取用户列表,读取完毕后,务必记得关闭流。
public List readJsonStream (InputStream in) throws IOException {
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8" ));
try {
return readUserArray(reader);
} finally {
reader.close();
}
}
public List readUserArray (JsonReader reader) throws IOException {
List users = new ArrayList();
reader.beginArray();
while (reader.hasNext()) {
users.add(readUser(reader));
}
reader.endArray();
return users;
}
public User readUser (JsonReader reader) throws IOException {
String name = null ;
int age = -1 ;
List geo=null ;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
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 readDoublesArray (JsonReader reader) throws IOException {
List doubles = new ArrayList();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
我们不难发现如下规律,每次读取数组或者对象之前,都必须调用beginObject()
或者beginArray()
,读完相应内容后,也必须调用endObject()
或者endArray()
。reader.hasNext()
用来判断是否还有下一个元素,然后调用nextName
来取下一个属性名,以及一系列的nextXXX
来取相应的值。 上面介绍的是将json字符串转换为java对象的用法,现在来看看如何使用JsonWriter来讲java对象转为json字符串。
public void writeJsonStream (OutputStream out, List users) throws IOException {
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8" ));
writer.setIndent(" " );
writeUsersArray(writer, users);
writer.close();
}
public void writeUsersArray (JsonWriter writer, List users) throws IOException {
writer.beginArray();
for (User user : users) {
writeUser(writer, user);
}
writer.endArray();
}
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 doubles) throws IOException {
writer.beginArray();
for (Double value : doubles) {
writer.value(value);
}
writer.endArray();
}
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
27
28
29
30
31
32
33
34
35
36
37
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
27
28
29
30
31
32
33
34
35
36
37
JsonWriter用来写入JSON字符串的规则和JsonWriter大相径庭,每次写入数组或者对象之前,都必须调用beginObject()
或者beginArray()
,写完相应内容后,也必须调用endObject()
或者endArray()
。name(xx)
用来写入名字,value(XX)
用来写入值。 接下来,深入浅出解析源码!stream包的结构如下: 枚举类JsonToken
的源码如下,主要用于表示JSON字符串中的名字/值的结构。
public enum JsonToken {
BEGIN_ARRAY,
END_ARRAY,
BEGIN_OBJECT,
END_OBJECT,
NAME,
STRING,
NUMBER,
BOOLEAN,
NULL,
END_DOCUMENT
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
JsonScope是一个常量类,元素词法作用域。用来标识JsonReader/JsonWriter现在读/写到哪了。
final class JsonScope {
static final int EMPTY_ARRAY = 1 ;
static final int NONEMPTY_ARRAY = 2 ;
static final int EMPTY_OBJECT = 3 ;
static final int DANGLING_NAME = 4 ;
static final int NONEMPTY_OBJECT = 5 ;
static final int EMPTY_DOCUMENT = 6 ;
static final int NONEMPTY_DOCUMENT = 7 ;
static final int CLOSED = 8 ;
}
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
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
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 ];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在写一个对象之前,必须使用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;
return this ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
看完源码不由觉得有点失望,只是赋值给了deferredName,其他什么事也没做。那么到底什么时候写入name的。这还得从写入value看起。 value(XX)
有很多重载函数。 我们只看value(String)
这种。
public JsonWriter value (String value) throws IOException {
if (value == null ) {
return nullValue();
}
writeDeferredName();
beforeValue();
string(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();
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
读取下一个name
nextString/nextInt/nextBoolean/nextLong/nextDouble/nextNull
用来读取下一个对应的值。
skipValue
跳过下一个value
nextQuotedValue/nextUnquotedValue
用来读取下一个单引号/双引号没有引号括起来的name或者string value
beginObject/endObject/beginArray/endArray
用来消费下一个对应类型的字符
Gson中的泛型
在了解Gson中的泛型前,我们来看两个类,$ Gson$ Types和$ Gson$ Preconditions。 $ Gson$ Types,专门用来处理泛型类型。核心源码如下:
public static Type canonicalize (Type type) {
if (type instanceof 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 {
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) {
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);
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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 checkNotNull (T obj) {
if (obj == null ) {
throw new NullPointerException();
}
return obj;
}
public static void checkArgument (boolean condition) {
if (!condition) {
throw new IllegalArgumentException();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
现在回过来了解Gson中的泛型,Gson中用TypeToken来表示泛型。 源码如下:
public class TypeToken <T > {
final Class super T> rawType;
final Type type;
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;
}
}
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
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
由于Java中只能通过getGenericSuperclass
获取父类泛型类型,所以TypeToken必须new出一个子类Type type= new TypeToken>(){}.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;
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);
}
public JsonPrimitive (String string) {
setValue(string);
}
public JsonPrimitive (Character c) {
setValue(c);
}
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;
}
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Gson中的TypeAdapter
还记得介绍注解时提到的TypeAdapter吗?TypeAdapter是一个抽象类,可以用来自定义类型转换。源码如下。
public abstract class TypeAdapter <T > {
public abstract void write (JsonWriter out, T value) throws IOException;
public abstract T read (JsonReader in) throws IOException;
public final TypeAdapter nullSafe () {
return new TypeAdapter() {
@Override public void write (JsonWriter out, T value) throws IOException {
if (value == 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);
}
};
}
}
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
27
28
29
30
31
32
33
34
35
36
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
27
28
29
30
31
32
33
34
35
36
我们只需继承于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 ]);
}
}
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
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
第二种方法,使用nullSafe
:
Gson gson= new GsonBuilder()
.registerTypeAdapter(User.class,new UserJsonAdapter().nullSafe())
.create();
TypeAdapterFactory是一个创造TypeAdapter的工厂,用来创造一些相似类型的TypeAdapter。
public interface TypeAdapterFactory {
TypeAdapter create(Gson gson, TypeToken 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
序列化策略
LongSerializationPolicy 枚举类,指定长整型的序列化类型,默认有DEFAULT,STRING两种类型,可继承它实现其他类型
InstanceCreator 实例创造器 当反序列化时需要实例化对象,但是假如该对象没有默认构造方法怎么吧?那么就自定义自己的实例创造器。InstanceCreator一般配合ConstructorConstructor一起使用。
public interface InstanceCreator <T > {
public T createInstance (Type type);
}
class UserInstanceCreator implements InstanceCreator {
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.0 d;
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;
private List serializationStrategies = Collections.emptyList();
private List deserializationStrategies = Collections.emptyList();
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
所有的方法如下:
Primitives 一个工具类,用于在原始类型和包装类型间转化。wrap
包装,unwrap
解开。
ObjectConstructor 一个人通用的构造器接口。
public interface ObjectConstructor <T > {
public T construct ();
}
ConstructorConstructor 保存实例构造器集合的类
public final class ConstructorConstructor {
private final Map> instanceCreators;
public ObjectConstructor get (TypeToken typeToken) {
final Type type = typeToken.getType();
final Class super T> rawType = typeToken.getRawType();
final InstanceCreator typeCreator = (InstanceCreator) instanceCreators.get(type);
if (typeCreator != null ) {
return new ObjectConstructor() {
@Override public T construct () {
return typeCreator.createInstance(type);
}
};
}
final InstanceCreator rawTypeCreator =
(InstanceCreator) instanceCreators.get(rawType);
if (rawTypeCreator != null ) {
return new ObjectConstructor() {
@Override public T construct () {
return rawTypeCreator.createInstance(type);
}
};
}
ObjectConstructor defaultConstructor = newDefaultConstructor(rawType);
if (defaultConstructor != null ) {
return defaultConstructor;
}
ObjectConstructor defaultImplementation = newDefaultImplementationConstructor(type, rawType);
if (defaultImplementation != null ) {
return defaultImplementation;
}
return newUnsafeAllocator(type, rawType);
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
JsonStreamParser 解析器,解析为JsonElement。hasNext
:是否有下一个元素,next
取下一个元素,返回JsonElement。
Streams 内部使用TypeAdapters.JSON_ELEMENT
写入/读取下一个JsonElement。
GSON 源码解读
构造方法
现在我们从Gson的构造方法入手,解读Gson是如何工作的。
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
final Map> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy,
List typeAdapterFactories) {
this .constructorConstructor = new ConstructorConstructor(instanceCreators);
this .excluder = excluder;
this .fieldNamingStrategy = fieldNamingStrategy;
this .serializeNulls = serializeNulls;
this .generateNonExecutableJson = generateNonExecutableGson;
this .htmlSafe = htmlSafe;
this .prettyPrinting = prettyPrinting;
this .lenient = lenient;
List factories = new ArrayList();
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
factories.add(excluder);
factories.addAll(typeAdapterFactories);
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
TypeAdapter longAdapter = longAdapter(longSerializationPolicy);
factories.add(TypeAdapters.newFactory(long .class, Long.class, longAdapter));
factories.add(TypeAdapters.newFactory(double .class, Double.class,
doubleAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.newFactory(float .class, Float.class,
floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
factories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
factories.add(TypeAdapters.URL_FACTORY);
factories.add(TypeAdapters.URI_FACTORY);
factories.add(TypeAdapters.UUID_FACTORY);
factories.add(TypeAdapters.CURRENCY_FACTORY);
factories.add(TypeAdapters.LOCALE_FACTORY);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);
factories.add(TimeTypeAdapter.FACTORY);
factories.add(SqlDateTypeAdapter.FACTORY);
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
factories.add(TypeAdapters.CLASS_FACTORY);
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
this .jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this .factories = Collections.unmodifiableList(factories);
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
构造方法让人看的眼花缭乱,尤其是往集合中加入了那么多的TypeAdapterFactory。由于是在太多无法逐一介绍。就挑个最简单的来讲解。总之明白TypeAdapter的作用即可。 ObjectTypeAdapter:内部有一个静态工厂类,所以只需ObjectTypeAdapter.FACTORY
这样调用即可。
public final class ObjectTypeAdapter extends TypeAdapter <Object > {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@Override public TypeAdapter create (Gson gson, TypeToken type) {
if (type.getRawType() == Object.class) {
return (TypeAdapter) new ObjectTypeAdapter(gson);
}
return null ;
}
};
接口的实现方法如下:
@Override public Object read (JsonReader in) throws IOException {
JsonToken token = in.peek();
switch (token) {
case BEGIN_ARRAY:
List list = new ArrayList();
in.beginArray();
while (in.hasNext()) {
list.add(read(in));
}
in.endArray();
return list;
case BEGIN_OBJECT:
Map map = new LinkedTreeMap();
in.beginObject();
while (in.hasNext()) {
map.put(in.nextName(), read(in));
}
in.endObject();
return map;
case STRING:
return in.nextString();
case NUMBER:
return in.nextDouble();
case BOOLEAN:
return in.nextBoolean();
case NULL:
in.nextNull();
return null ;
default :
throw new IllegalStateException();
}
}
@Override public void write (JsonWriter out, Object value) throws IOException {
if (value == null ) {
out.nullValue();
return ;
}
TypeAdapter typeAdapter = (TypeAdapter) gson.getAdapter(value.getClass());
if (typeAdapter instanceof ObjectTypeAdapter) {
out.beginObject();
out.endObject();
return ;
}
typeAdapter.write(out, value);
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
关于TypeAdapter这里就不继续深究了,预定义的TypeAdapter实在太多了。其中JsonAdapterAnnotationTypeAdapterFactory
用来处理@JsonAdapter
注解,ReflectiveTypeAdapterFactory
用来反射获取字段等等。
getAdapter
将Java对象序列化为Json字符串时,需要调用gson.getAdapter(XX)
来获取相应类型的转换器,然后按照TypeAdapter中规定好的规则进行序列化/反序列化。
public TypeAdapter getAdapter (TypeToken type) {
TypeAdapter> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null ) {
return (TypeAdapter) cached;
}
Map, FutureTypeAdapter>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false ;
if (threadCalls == null ) {
threadCalls = new HashMap, FutureTypeAdapter>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true ;
}
FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
if (ongoingCall != null ) {
return ongoingCall;
}
try {
FutureTypeAdapter call = new FutureTypeAdapter();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter candidate = factory.create(this , type);
if (candidate != null ) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
以上源码的流程是这样的。首先从typeTokenCache
中获取看看有没有相应类型的Adapter,第一次肯定没有,然后利用中间变量FutureTypeAdapter
,从工厂中遍历去取,然后放入typeTokenCache
中。FutureTypeAdapter
是一个代理TypeAdapter,内部还是原TypeAdapter进行处理。
toJson
终于快接近尾声了,现在来看toJson
方法的内部原理,到底是怎么一步步将对象转为Json字符串的。最终调用的是toJson(Object src, Type typeOfSrc, JsonWriter writer)
方法,通过相应的Adapter进行读写。
public String toJson (Object src) {
if (src == null ) {
return toJson(JsonNull.INSTANCE);
}
return toJson(src, src.getClass());
}
public String toJson (Object src, Type typeOfSrc) {
StringWriter writer = new StringWriter();
toJson(src, typeOfSrc, writer);
return writer.toString();
}
public void toJson (Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
try {
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
toJson(src, typeOfSrc, jsonWriter);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
public void toJson (Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
TypeAdapter> adapter = getAdapter(TypeToken.get(typeOfSrc));
boolean oldLenient = writer.isLenient();
writer.setLenient(true );
boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(serializeNulls);
try {
((TypeAdapter) adapter).write(writer, src);
} catch (IOException e) {
throw new JsonIOException(e);
} finally {
writer.setLenient(oldLenient);
writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls);
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
fromJson
public T fromJson (String json, Class classOfT) throws JsonSyntaxException {
Object object = fromJson(json, (Type) classOfT);
return Primitives.wrap(classOfT).cast(object);
}
public T fromJson (String json, Type typeOfT) throws JsonSyntaxException {
if (json == null ) {
return null ;
}
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
public T fromJson (Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
JsonReader jsonReader = newJsonReader(json);
T object = (T) fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
return object;
}
public T fromJson (JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true ;
boolean oldLenient = reader.isLenient();
reader.setLenient(true );
try {
reader.peek();
isEmpty = false ;
TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
TypeAdapter typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
} finally {
reader.setLenient(oldLenient);
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
GsonBuilder
GsonBuilder用来对Gson进行配置,比如注册TypeAdapter等等。最后调用create()
返回Gson对象。
最后
Gson内部的Json与Java间的转换依赖于各类的TypeAdapter,通过registerTypeAdapter可以注册新的类型转换器,实例创造器的等。越先注册的优先级就越高。当然,如果你没有注册Adapter,对于自定义的对象一般参与转换的Adapter是ReflectiveTypeAdapterFactory
。有兴趣的请自行阅读源码。 registerTypeAdapter的源码如下:
public GsonBuilder registerTypeAdapter (Type type, Object typeAdapter) {
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
|| typeAdapter instanceof JsonDeserializer>
|| typeAdapter instanceof InstanceCreator>
|| typeAdapter instanceof TypeAdapter>);
if (typeAdapter instanceof InstanceCreator>) {
instanceCreators.put(type, (InstanceCreator) typeAdapter);
}
if (typeAdapter instanceof JsonSerializer> || typeAdapter instanceof JsonDeserializer>) {
TypeToken> typeToken = TypeToken.get(type);
factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
}
if (typeAdapter instanceof TypeAdapter>) {
factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
}
return this ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
本期解读到此结束,由于篇幅问题,Gson中预定义的TypeAdapter实在太多就不进行分析了。