http://www.jianshu.com/p/89c314ae8c0b
介绍
Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。
基本概念
- Serialization:序列化,使Java对象到Json字符串的过程。
- Deserialization:反序列化,字符串转换成Java对象。
- JSON数据中的JsonElement有下面这四种类型:
JsonPrimitive —— 例如一个字符串或整型
JsonObject—— 一个以 JsonElement 名字(类型为 String)作为索引的集合。也就是说可以把 JsonObject 看作值为 JsonElement 的键值对集合。
JsonArray—— JsonElement 的集合。注意数组的元素可以是四种类型中的任意一种,或者混合类型都支持。
JsonNull—— 值为null
gson解决的问题
- 提供一种像toString()和构造方法的很简单的机制,来实现Java 对象和Json之间的互相转换。
- 允许已经存在的无法改变的对象,转换成Json,或者Json转换成已存在的对象。
- 允许自定义对象的表现形式;
- 支持任意的复杂对象;
- 能够生成可压缩和可读的Json的字符串输出。
gson注解
源码分析
Gson其实就是一套模型转换工具,他的一端连接的是json数据格式编码流,另一头就是我们的Java对象模型。我们先给自己找一个入口点,看下Gson一个常见的例子:
public static class ClassRoom {
public String roomName;
public int number;
public String toString() {
return "[" + roomName + ":" + number + "]";
}
}
public static class User {
public String name;
public int age;
private ClassRoom room;
@Override
public String toString() {
// TODO Auto-generated method stub
return name + "->" + age + ":" + room;
}
}
我们尝试传入一个json格式的数据串
Gson gson = new Gson();
String strJson = "{name:'david',age:19,room:{roomName:'small',number:1}}";
User u = gson.fromJson(strJson, User.class);
在上述代码中,gson相当于起到了一个数据适配器的作用,将一个Json的数据格式转换为一个Java业务可用的数据模型。而这一层的转换,是通过Gson的fromJson方法实现的。
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;
}
Gson支持以流的方式来读取字符,为了接口的复用性,如果你的第一个参数输入的是一个String对象,Gson一样会将它包装成为一个流对象StringReader。Gson的fromJson会调用到统一的接口方法 T fromJson(JsonReader reader, Type typeOfT) 中去:
//code 2
public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);//不严格按照Json标准语法
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) {
............
}
}
在code2代码主要做了下面的事情:
- 我们传入的一个StringReader,将会再次被包装成为一个Json语法格式的JsonReader对象;
- 通过调用setLenient方法,给Json语法提供更加大的宽容度;
- 通过reader.peek方法,先做一次语法检查,并获取第一个非空字符,通过这个非空字符来标记下一个解析格式;
- 通过传入的类型Type,来获取这个类型对应的TypeToken;
- 通过生成的TypeToken来生成对应的适配器;(Gson的作用,是将Json数据模型往不同平台上的Java对象转换,实际上可以算是一种平台接口的转换,这里,Gson用了适配器的方式来实现这套方案)。
我们来一步步地看下代码,代码一进来,reader就调用了一个peek操作,这是为什么呢?我们知道,在流式对象中,peek的目的是为了查看下一个字符,JsonReader也自然如此。JsonReader通过一次peek先做一个简单的语法校验,然后标注当前JsonReader解析的时候将以何种形式解析。
//code3
public JsonToken peek() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
....
}
peek方法并不像我们之前的流式文件那样,返回一个真实的数据,而是返回一个当前的解析状态标识JsonToken。JsonToken是一个枚举类型,用来标识在Json数据格式中的各种语法单位。而在peek()函数的内部,又调用了一个doPeek()。虽然两个名字非常相同,但是返回的结果却是完全不同。doPeek是真正意义上的返回数据,也就是返回一个真实的字符:
//code doPeek()
private int doPeek() throws IOException {
stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
switch (c) {
case '"':
return peeked = PEEKED_DOUBLE_QUOTED_NAME;
case '\'':
checkLenient();
return peeked = PEEKED_SINGLE_QUOTED_NAME;
case '}':
if (peekStack != JsonScope.NONEMPTY_OBJECT) {
return peeked = PEEKED_END_OBJECT;
} else {
throw syntaxError("Expected name");
}
default:
}
}
在doPeek()函数中,需要用到一个叫做stack变量的数据,里面存放的是叫做JsonScope的一堆常量。这是因为,Gson对Json的解析方式,是采用栈式的解析,按照层次解析的方式,这种层次解析的方式需要用栈来记录一些先前的状态。而这个stack的初始值,在一个初始代码块中设置:
private int[] stack = new int[32];
public int stackSize = 0;
{
stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
}
可见,stack初始栈顶数据为EMPTY_DOCUMENT常量。这时候,我们回到doPeek函数中去。我们可以看到:
- if将调用line1中的方法体。将栈顶数据替换为NONEMPTY_DOCUMENT状态
- 在line2中获取下一个非空白字符,赋值给c变量
- 在line3中将执行case '{'将PEEKED_BEGIN_OBJECT 整型常量付给peeked变量,然后返回。
然后我们返回我们的peek()方法:
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
switch (p) {
case PEEKED_BEGIN_OBJECT:
return JsonToken.BEGIN_OBJECT;
}
doPeek方法返回一个整型的常量后,peek方法又通过这个整型常量转化为对应的JsonToken变量。或许有些看官就会问了,如果是这样的话,JsonToken的意义何在呢?你完全可以用返回的peeked变量来代替JsonToken的数据?
case PEEKED_SINGLE_QUOTED_NAME:
case PEEKED_DOUBLE_QUOTED_NAME:
case PEEKED_UNQUOTED_NAME:
return JsonToken.NAME;
我们可以看到,三种peek出来的数据类型,实际上可能对应一种Json中的标识符,那么,也就是说peek出来的符号类型(整型常量)跟Json中的标识符(JsonToken枚举常量),实际上是一种多对应的数据关系,所以不能混用。另外,我们在peek()方法中所生成的这个JsonToken,在Reader中并没有记录,也就是说,对于数据的解析,Reader还是关心doPeek方法中生成的中间状态数据。
我们回到code2中,根据上面的分析,我们已经知道reader.peek()方法实际上是初始了一些数据变量。接下去,fromJson方法将通过TypeToken.get的静态方法来生成一个TypeToken对象。
public static TypeToken> get(Type type) {
return new TypeToken
TypeToken的get方式,是一种静态构造工厂,它将直接返回一个TypeToken对象。
Gson gson = new Gson();
String strJson = "{name:'david',age:19,room:{roomName:'small',number:1}}";
User u = gson.fromJson(strJson, User.class);
当TypeToken.get(User.class)的时候,返回的就是一个内部持有一个User.class为Type的TypeToken变量,在通过TypeToken.get(Type)方法调用以后,将会通过一个叫getAdapter的方法来获得typeAdapter对象。
TypeAdapter是Gson代码体系中的重中之重,它承担了真正意义上的转换工作。
Gson在Adapter的管理上,利用了享元 ,毕竟,解析类结构有一定的时间消耗,为了降低这种时间上的开销,Gson使用了缓冲池来管理这种映射关系。或许读者有一个问题:既然TypeToken.get方法每次都是利用静态工厂的方式构造一个新的TypeToken,那么你在放入cache中并不能起到cache的作用?
答案是:可以的。回答这个问题,我们需要回到TypeToken的源码:
@Override
public final int hashCode() {
return this.hashCode;
}
@Override
public final boolean equals(Object o) {
return o instanceof TypeToken> && $Gson$Types.equals(type, ((TypeToken>) o).type);
}
如上述代码显示,TypeToken利用相同的hashCode和复写的equals方法,来解决不同对象的冲突问题。好的,我们继续回到getAdapter方法:
// code Gson.getAdapter
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;
}
// the key and value type parameters always agree
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();
}
}
}
当cache中并不存在需要的适配器的时候,并且该线程并不存在有缓冲池对象的时候,Gson将构造一个Map对象,放入线程中。同时我们还可以发现Gson的Cache的特点:
- 在Gson的Cache管理里,实际上应用了二级缓冲;
- Gson对象内部有一个缓冲,而Gson对象所在的线程又有一个共享Cache;
- 在不同的线程之间,又使用不同的cache。
//核心代码
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;
}
}
Adapter的构造是通过遍历一个factories集合类来完成的。做法也很简单,Factory通过匹配传入的TypeToken类型,然后是否匹配,如果匹配将生成对象,不匹配就返回null。同时,一旦生成Adapter对象,程序立马返回,说明构造对象是有优先级别的,可能你的AFactory通过规则可以生成对象,BFactory通过规则也可以生成对象,那么这个时候如果AFactory在BFactory的前面,那么将优先使用AFactory来构造Adapter。
factories的初始化数据在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)
{
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);//针对JsonElement类做特别处理
factories.add(ObjectTypeAdapter.FACTORY);//针对Object类做特殊处理
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);//用于拦截一些不在使用的类型
// user's type adapters
factories.addAll(typeAdapterFactories);
// type adapters for basic platform types
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);
// type adapters for composite and user-defined types
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);
}
,当我们传入一个User.class类型的时候,Gson会通过ReflectiveTypeAdapterFactory工厂来生产一个Adapter来适配Json对象:
public TypeAdapter create(Gson gson, final TypeToken type) {
Class super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {//拦截基本类型
return null; // it's a primitive!
}
ObjectConstructor constructor = constructorConstructor.get(type);//获取构造器
return new Adapter(constructor, getBoundFields(gson, type, raw));
}
其他
Gson gson = new GsonBuilder()
//序列化null
.serializeNulls()
// 设置日期时间格式,另有2个重载方法
// 在序列化和反序化时均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化内部类
.disableInnerClassSerialization()
//生成不可执行的Json(多了 )]}' 这4个字符)
.generateNonExecutableJson()
//禁止转义html标签
.disableHtmlEscaping()
//格式化输出
.setPrettyPrinting()
.create();