Gson在Android开发中,我们经常用到,主要用于把服务端给我们返回的json字符串,解析成相应的实体类,我们今天来看一下源码。
Gson通常是创建一个实例,然后调用toJson和fromJson方法使用。Gson实例是线程安全的,你可以在多线程中重用它
如果你只需要默认的配置,你可以通过调用new Gson()来创建一个默认的实例。你也可以自定义配置,通过调用GsonBuilder来创建Gson实例。
Gson gson = new Gson();
Type listType = new TypeToken<List<String>>(){}.getType();
List<String> target = new LinkedList<>();
target.add("blah");
String json = gson.toJson(target,listType); //序列化
List<String> target2 = gson.fromJson(json,listType); //反序列化
关于TypeToken的问题
Type listType = new TypeToken<List<String>>(){}.getType();
创建TypeToken对象后面加了大括号,表示我们创建了一个匿名内部类。我们点进去TypeToken源码进去看一下
我们看这个构造器的修饰符是protected,不是public
/**
* Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
*
* @param jsonElement root of a tree of {@link JsonElement}s
* @return JSON String representation of the tree
* @since 1.4
*/
public String toJson(JsonElement jsonElement) {
StringWriter writer = new StringWriter();
toJson(jsonElement, writer);
return writer.toString();
}
/**
* Writes out the equivalent JSON for a tree of {@link JsonElement}s.
*
* @param jsonElement root of a tree of {@link JsonElement}s
* @param writer Writer to which the Json representation needs to be written
* @throws JsonIOException if there was a problem writing to the writer
* @since 1.4
*/
public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
try {
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
toJson(jsonElement, jsonWriter);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
这个方法是把实体序列化,转化为json字符串
TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc)); //获取类型的TypeAdapter
/**
* Returns the type adapter for {@code} type.
*
* @throws IllegalArgumentException if this GSON cannot serialize and
* deserialize {@code type}.
*/
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
我们把String 转换成实体类,通常都这么写
Gson gson = new Gson();
String strJson = "{name:"1"}";
UserBean userBean = gson.fromJson(strJson, UserBean.class);
我们来看一下fromJson这个方法
@SuppressWarnings("unchecked")
public <T> 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支持以流的方式来读取字符
我们继续看源码
public <T> 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<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
throw new JsonSyntaxException(e);
} finally {
reader.setLenient(oldLenient);
}
}
通过传入的类型Type,来获取这个类型对应的TypeToken
通过TypeToken来生成对应的适配器
最终转化成Object对象
Java在运行时,泛型参数的类型会被擦除,导致在运行期间所有的泛型类型都是Object类型
我们在代码中测试下:
List<String> listStr = new ArrayList<>();
List<Integer> listInt = new ArrayList<>();
Log.i("test-----", String.valueOf(listStr.getClass()));
Log.i("test----", String.valueOf(listInt.getClass()));
Log.i("test----", String.valueOf(listInt.getClass().isAssignableFrom(listStr.getClass())));
运行结果:
01-09 09:03:23.037 11017-11017/? I/test-----: class java.util.ArrayList
01-09 09:03:23.037 11017-11017/? I/test----: class java.util.ArrayList
01-09 09:03:23.037 11017-11017/? I/test----: true
说明Java运行时,泛型参数类型被擦除了
所以我再把数据转换成List型,要这么写
Type listType = new TypeToken<List<String>>(){}.getType();
List<String> target = new LinkedList<>();
target.add("blah");
List<String> target2 = gson.fromJson(json,listType); //反序列
TypeToken 类是用来解决java运行时泛型类型被擦除的,通过TypeToken可以获得具体的参数类型
我们在代码中测试一下:
List<String> list = new ArrayList<>();
TypeToken<ArrayList<String>> typeToken = new TypeToken<ArrayList<String>>(){};
Log.i("test------", String.valueOf(typeToken.getType()));
运行结果:
I/test------: java.util.ArrayList<java.lang.String>