本文已收录到 AndroidFamily,技能和职场问题,请关注大众号 [彭旭锐] 提问。
前言
大家好,我是小彭。
Gson 是 Google 推出的 Java Json 解析库,具有接入成本低、运用快捷、功用扩展性杰出等长处,想必大家都很熟悉了。在这篇文章里,咱们将评论 Gson 的根本用法和以及主要流程的源码剖析。
学习路线图:
1. Gson 的根本运用
Gradle 依赖
dependencies {
implementation 'com.google.code.gson:gson:2.10'
}
1.1 GsonBuilder 装备项
Gson 类是整个库的中心 API,在进行任何序列化或反序列化之前,咱们都需求获得一个 Gson 目标。能够直接 new 创立默许装备的 Gson 目标,也能够运用 GsonBuilder 结构者装备 Gson 目标。
事实上,一个 Gson 目标代表一个 Gson 作业环境,不同 Gson 目标之间的装备和缓存都不会复用。 因而,在项目中有必要在 common 层供给一个全局的 Gson 目标,既有利于统一序列化装备,也是 Gson 功能优化的根本保障。
GsonBuilder 运用示例
Gson gson = new GsonBuilder()
// 设置自定义解析(不支撑协变)
.registerTypeAdapter(Id.class, new IdTypeAdapter())
// 设置自定义解析(支撑协变)
registerTypeHierarchyAdapter(List.class, new MyListTypeAdapter())
// 设置自定义解析(以工厂方式)
.registerTypeAdapterFactory(new IdTypeAdapterFactory())
// 设置日期格局
.setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
// 设置主动切换命名风格规矩(默许不切换命名风格)
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
// 设置过滤指定字段标识符(默许只过滤 transient 和 static 字段)
.excludeFieldsWithModifiers(Modifier.TRANSIENT | Modifier.STATIC)
// 设置类或字段过滤规矩
.setExclusionStrategies(new MyExclusionStrategy1())
// 设置过滤规矩(只适用于序列化)
.addSerializationExclusionStrategy(new MyExclusionStrategy2())
// 设置过滤规矩(只适用于反序列化)
.addDeserializationExclusionStrategy(new MyExclusionStrategy3())
// 设置序列化版别号
.setVersion(1.0)
// 启用非根底类型 Map Key
.enableComplexMapKeySerialization()
// 启用不过滤空值(默许会过滤空值)
.serializeNulls()
// 启用 Json 格局化
.setPrettyPrinting()
.create();
1.2 注解装备
Gson 没有编译时处理,所以注解均是运行时注解。
-
@SerializedName 字段别号: 支撑设置多个别号,
value
变量在序列化和反序列化时都有用,而alternate
变量仅仅在反序列化时做兼容罢了; -
@Expose 字段露出:
- 默许状况下,一个类中一切字段都会露出,但运用 @Expose 注解后,只有声明注解的字段才会露出;
- 注解的
serialize
变量或deserialize
变量能够声明字段只参加序列化或反序列化,默许都参加。
- @JsonAdapter 注解: 声明在详细类或字段上,用于更细粒度地设置 TypeAdapter,优先级比 registerTypeAdapter 高;
- @Since 注解: 声明在详细类或字段上,声明字段的起始序列化版别;
- @Until 注解: 声明在详细类或字段上,声明字段的停止序列化版别。当字段的序列化版别满意 since ≥ GsonBuilder#setVersion 且 GsonBuilder#setVersion ≤ until 时,才会参加序列化;
1.3 JsonSerializer 和 JsonDeserializer 自定义解析
JsonSerializer
和 JsonDeserializer
是 Gson 1.x 版别供给的自定义解析 API,是根据树型结构的解析 API。在解析数据时,它们会将 Json 数据一次性解析为 JsonElement
树型结构。 JsonElement 代表 Json 树上的一个节点,有 4 种详细类型:
JsonElement | 描述 |
---|---|
JsonObject | {} 目标 |
JsonArray | [] 数组 |
JsonPrimitive | 根本类型 |
JsonNull | null 值 |
1.4 TypeAdapter 自定义解析
TypeAdapter
是 Gson 2.0 新增的自定义解析 API,是根据流式结构的 API。事实上, JsonSerializer 和 JsonDeserializer 最终也会被结构为 TreeTypeAdapter
;
相较之下,JsonSerializer & JsonDeserializer 相对方便,但更费内存。而 TypeAdapter 更节约内存,但不方便。不过,假如需求用到完整数据结构(例如依据 type 字段依照不同类型解析 data),也能够手动解析为树型结构。因而 TypeAdapter 这个 API 的优先级更高。
TypeAdapter | JsonSerializer、JsonDeserializer | |
---|---|---|
引进版别 | 2.0 | 1.x |
Stream API | 支撑 | 不支撑 |
Tree API | 支撑,能够手动转化 | 支撑 |
内存占用 | 小 | 比 TypeAdapter 大 |
效率 | 高 | 比 TypeAdapter 低 |
效果范围 | 序列化 + 反序列化 | 序列化 / 反序列化 |
1.5 registerTypeAdapter 和 registerTypeHierarchyAdapter 的差异
-
registerTypeAdapter 是不变型的: 只会对注册的类型收效。例如注册
<List.class,TypeAdapter>
,则只会影响List
类型的字段,但不会影响 ArrayList 类型的字段; -
registerTypeHierarchyAdapter 是协变型的: 会对注册的类型及其子类收效。例如注册
<List.class,TypeAdapter>
,则只会影响List
、ArrayList
类型的字段;
registerTypeAdapter | registerTypeHierarchyAdapter | |
---|---|---|
支撑泛型 | 是 | 否 |
支撑承继 | 否 | 是 |
2. Gson 源码剖析
这一节,咱们来剖析 Gson 中心流程的作业原理和源码。
2.1 说一下 Gson 解析的作业进程
“TypeAdapter” 是 Gson 解析的重要人物,Gson 每次解析一种目标类型,首要需求创立一个 TypeAdapter 目标,之后一切的解析作业都会交给其中的 TypeAdapter#write 和 TypeAdapter#read 办法;
Java Bean 类型的 TypeAdapter 目标是交给 “ReflectiveTypeAdapterFactory” 创立的。每创立一种类型的 TypeAdapter,都需求递归地运用 “反射” 遍历一切字段,并解析字段上的注解,生成一个 <serializeName - BoundFiled>
的映射表。
- 在序列化时,首要运用反射获取字段值,再运用字段的
BoundFiled
序列化; - 在反序列化时,首要创立目标实例(下文会评论怎么创立),再运用顺次运用字段的
BoundField
反序列为字段类型的值,再经过反射为字段赋值。
由于字段值的写入和读取是经过 Field
元数据反射操作的,所以 private 字段也能够操作。
在结构 Gson 目标时,现已初始化了一系列 TypeAdapter 创立工厂,开发者能够注册自定义的 TypeAdapter:
Gson.java
Gson(final Excluder excluder, ...) {
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// 过滤规矩
factories.add(excluder);
// 自定义 TypeAdapter
factories.addAll(factoriesToBeAdded);
// 1. 根底类型
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
...
// 2. 复合类型
// 2.1 列表类型
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
// 2.2 调集类型
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
// 2.3 枚举类型
factories.add(TypeAdapters.ENUM_FACTORY);
// 2.4 Java Bean 类型
factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
}
经过 Gson#getAdapter 查找匹配 TypeAdapter 的办法:
Gson.java
// TypeAdapter 缓存映射表 <Type - TypeAdapter>
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
// 先从映射表缓存中查找
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
// 再经过 TypeAdapter 创立工厂创立,并参加映射表缓存中
for (TypeAdapterFactory factory : factories) {
// 早年到后线性扫描创立工厂,找到合适的 TypeAdapter
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
// 参加缓存中
typeTokenCache.put(type, candidate);
return candidate;
}
}
}
运用 ReflectiveTypeAdapterFactory 工厂为每种类型创立 TypeAdapter 目标:
ReflectiveTypeAdapterFactory.java
// 1. 创立 TypeAdapter 目标
@Override
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
// 检查是否为 Object 类型
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
// 1.1 获取目标结构器(下文剖析)
ObjectConstructor<T> constructor = constructorConstructor.get(type);
// 1.2 getBoundFields:解析每个字段的适配器
// 1.3 FieldReflectionAdapter:TypeAdapter 目标(Adapter 类型)
return new FieldReflectionAdapter<T>(constructor, getBoundFields(gson, type, raw));
}
public static abstract class Adapter<T, A> extends TypeAdapter<T> {
final Map<String, BoundField> boundFields;
// 2. 反序列化进程
@Override
public T read(JsonReader in) {
// 2.1 创立目标
T instance = constructor.construct();
// 2.2 消费 {
in.beginObject();
// 2.3 递归反序列化每个字段
while (in.hasNext()) {
String name = in.nextName();
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
// 读取流并设置到 instance 目标中
readIntoField(in, instance);
}
}
// 2.4 消费 }
in.endObject();
return instance;
}
// 3. 序列化进程
@Override
public void write(JsonWriter out, T value) {
// 3.1 写入 {
out.beginObject();
// 3.2 递归序列化每个字段
for (BoundField boundField : boundFields.values()) {
// 将目标的每个字段写入流中
boundField.write(out, value);
}
// 3.3 写入 }
out.endObject();
}
}
// -> 1.2 getBoundFields:解析每个字段的适配器
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw, boolean blockInaccessible, boolean isRecord) {
// 1.2.1 映射表
Map<String, BoundField> result = new LinkedHashMap<>();
if (raw.isInterface()) {
return result;
}
...
// 1.2.2 遍历一切 Field
Field[] fields = raw.getDeclaredFields();
for (Field field : fields) {
// 1.2.2.1 字段过滤
boolean serialize = includeField(field, true);
boolean deserialize = includeField(field, false);
if (!serialize && !deserialize) {
continue;
}
// 1.2.2.2 获取字段的一切别号,第 0 位是主称号
List<String> fieldNames = getFieldNames(field);
// 1.2.2.3 为一切字段别号创立 BoundField 目标
for (int i = 0, size = fieldNames.size(); i < size; ++i) {
String name = fieldNames.get(i);
// serialize = false 这一行阐明:序列化时是采用字段的主称号
if (i != 0) serialize = false;
BoundField boundField = createBoundField(context, field, accessor, name, TypeToken.get(fieldType), serialize, deserialize, blockInaccessible);
BoundField replaced = result.put(name, boundField);
if (previous == null) previous = replaced;
}
// 1.2.2.4 存在两个的字段运用相同 serializeName 的冲突
if (previous != null) {
throw new IllegalArgumentException(declaredType + " declares multiple JSON fields named " + previous.name);
}
}
// 1.2.3 回来映射表
return result;
}
// -> 1.2.2.3 为一切字段别号创立 BoundField 目标
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
final Gson context, final Field field, final String name,
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
// 根本类型
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
// @JsonAdapter 注解
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
TypeAdapter<?> mapped = null;
if (annotation != null) {
mapped = jsonAdapterFactory.getTypeAdapter(constructorConstructor, context, fieldType, annotation);
}
final boolean jsonAdapterPresent = mapped != null;
if (mapped == null) mapped = context.getAdapter(fieldType);
final TypeAdapter<?> typeAdapter = mapped;
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
@Override
void write(JsonWriter writer, Object value) {
if (!serialized) return;
// 经过反射读取字段值
Object fieldValue = field.get(value);
TypeAdapter t = jsonAdapterPresent ? typeAdapter : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
// 写出到流
t.write(writer, fieldValue);
}
@Override
void readIntoField(JsonReader reader, Object target) {
// 从流读取
Object fieldValue = typeAdapter.read(reader);
// 经过反射写入字段值
field.set(target, fieldValue);
}
};
}
2.2 List & Set & Map 等容器类型是怎么解析的?
- 1、在预置的容器 TypAdapter 中,会先经过容器类型的
RawType
获取容器结构器,再依据泛型实参elementType
获取元素类型的 TypeAdapter; - 2、在序列化时,先写入 [ 左中括号,再用元素类型的 TypeAdapter 顺次序列化元素目标,再写入 ] 右中括号;
- 3、在反序列化时,先创立调集目标,再用元素类型的 TypeAdapter 顺次反序列化元素目标;
- 4、Map 类型需求保护 Key 和 Value 两个 TypeAdapter。
CollectionTypeAdapterFactory.java
// 1. 创立 TypeAdapter
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
// 检查是否为列表类型
Class<? super T> rawType = typeToken.getRawType();
if (!Collection.class.isAssignableFrom(rawType)) {
return null;
}
// 1.1 解析元素类型
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
// 1.2 查找元素类型映射的 TypeAdapter
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
// 1.3 解析容器目标的结构器
ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);
// 1.4 包装新的 TypeAdapter
TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);
}
private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
// 2. 反序列化进程
@Override
public Collection<E> read(JsonReader in) {
// 2.1 创立容器目标
Collection<E> collection = constructor.construct();
// 2.2 消费 [
in.beginArray();
// 2.3 运用 1.2 进程的 TypeAdapter 反序列化每个元素
while (in.hasNext()) {
E instance = elementTypeAdapter.read(in);
collection.add(instance);
}
// 2.4 消费 ]
in.endArray();
return collection;
}
// 3. 序列化进程
@Override
public void write(JsonWriter out, Collection<E> collection) {
// 3.1 写入 [
out.beginArray();
// 3.2 运用 1.2 进程的 TypeAdapter 序列化每个元素
for (E element : collection) {
elementTypeAdapter.write(out, element);
}
// 3.3 写入 ]
out.endArray();
}
}
2.3 枚举类型是怎么解析的?
- 1、在预置的 EnumTypeAdapter 适配器中,会先获取枚举类型的整个枚举列表,并生成 2 个映射表。
- <name – 枚举> 映射表
- <枚举 – name> 映射表
- 2、在序列化时,会写入枚举的 name。在反序列化时,会依据 name 查询枚举目标。
TypeAdapters.java
private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
// <name - 枚举> 映射表
private final Map<String, T> nameToConstant = new HashMap<String, T>();
// <枚举 - name> 映射表
private final Map<T, String> constantToName = new HashMap<T, String>();
public EnumTypeAdapter(Class<T> classOfT) {
for (T constant : classOfT.getEnumConstants()) {
String name = constant.name()
nameToConstant.put(name, constant);
constantToName.put(constant, name);
}
}
@Override
public T read(JsonReader in) {
return nameToConstant.get(in.nextString());
}
@Override
public void write(JsonWriter out, T value) {
out.value(constantToName.get(value));
}
}
2.4 同类型嵌套会不会无限递归?
ReflectiveTypeAdapterFactory
在创立目标的 TypeAdapter 适配器时,需求递归的创立每个字段的 TypeAdapter。假如字段的类型正好与类的类型相同,那么又会触发创立一个相同的 TypeAdapter,形成无限递归。例如:
无限递归的例子
public class Article {
public Article linkedArticle;
}
剖析发现,无限递归只发生在第一次创立某个 Java Bean 类型的 TypeAdapter 时,而下一次会从缓存获取,不会发生无限递归。因而,Gson 的做法是:
- 1、在每次新创立 TypeAdapter 前,先在暂时映射表中创立一个
FutureTypeAdapter
署理目标。在创立实在的 TypeAdapter 后,将其注入到署理目标中。这样在递归获取字段的 TypeAdapter 时,就会拿到署理目标,而不是从头创立 TypeAdapter,因而处理递归问题; - 2、别的,考虑到多线程环境下,暂时映射表的新增和移除会有并发问题,因而 Gson 的策略是运用
ThreadLocal
隔离各个线程的暂时映射表。
Gson.java
// 线程隔离的映射表
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls = new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>();
// 线程同享的映射表(根据 ConrurrentHashMap)
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
// 1. 测验从缓存获取
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
// 2. 初始化当前线程的暂时映射表
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// 3. 测验从暂时映射表获取(递归调用时,会从这里获取到署理 TypeAdapter,而不会走到下面的 factory.create
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
// 4.1 创立署理 TypeAdapter
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
// 4.2 创立 TypeAdapter
TypeAdapter<T> candidate = factory.create(this, type);
// 4.3 将实在的 TypeAdapter 注入到署理 TypeAdapter 中
if (candidate != null) {
call.setDelegate(candidate);
// 4.4 将 TypeAdapter 写入缓存
typeTokenCache.put(type, candidate);
return candidate;
}
}
} finally {
// 5. 铲除暂时映射表
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
2.5 Gson 是怎么创立目标的?
- 1、根底类型:Integer、Calendar 等根底类型由固定的 TypeAdapter,会经过 new 关键字创立目标;
- 2、枚举:枚举的序列化和反序列化仅仅在枚举名 name 和枚举目标之间切换,不会创立新的枚举目标;
- 3、List & Set & Map:容器类型会经过预置的目标创立工厂,调用 new 关键字创立目标;
- 4、Java Bean:Java Bean 的创立分为多种或许:
- 状况 1:自定义了目标创立工厂
InstanceCreator
,则优先经过自定义工厂创立; - 状况 2:存在默许的无参结构函数,则经过反射结构函数创立;
- 状况 3:运用 Unsafe API 兜底创立目标。
- 状况 1:自定义了目标创立工厂
ConstructorConstructor.java
public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
final Type type = typeToken.getType();
final Class<? super T> rawType = typeToken.getRawType();
// InstanceCreator API
final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
if (typeCreator != null) {
return new ObjectConstructor<T>() {
@Override
public T construct() {
return typeCreator.createInstance(type);
}
};
}
final InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>) instanceCreators.get(rawType);
if (rawTypeCreator != null) {
return new ObjectConstructor<T>() {
@Override
public T construct() {
return rawTypeCreator.createInstance(type);
}
};
}
// 无参结构函数
ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
if (defaultConstructor != null) {
return defaultConstructor;
}
// 容器类型
ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
if (defaultImplementation != null) {
return defaultImplementation;
}
// Unsafe API
return newUnsafeAllocator(type, rawType);
}
2.6 Gson 隐藏的坑
当 Class 未供给默许的无参结构函数时,Gson 会运用 Unsafe API 兜底来创立目标。Unsafe API 主要供给一些用于履行低级别、不安全操作的办法,也供给了一个非常规实例化目标的 allocateInstance
办法。
这个 API 不会调用结构函数 ,因而相关的结构初始化操作会丢掉;
- 1、结构函数参数的默许值丢掉;
- 2、字段的默许值丢掉;
- 3、Kotlin 非空类型失效;
- 4、初始化块未履行;
- 5、by 特点署理(没有创立署理目标)
3. Gson 怎么解析泛型类型?
由于 Java 有泛型擦除,无法直接在 .class
语法上声明泛型信息,Gson 的办法是要求程序员创立匿名内部类,由 Gson 在运行时经过反射获取类声明上的泛型信息。
示例代码
// 非法:
Response<User> obj = Gson().fromJson<Response<User>>(jsonStr, Response<User>.class)
// 合法;
TypeToken token = object : TypeToken<Response<User>>() {}
Response<User> obj = Gson().fromJson<Response<User>>(jsonStr, token.type)
为什么反序列化泛型类要运用匿名内部类呢?
原理是 Class 文件中的 Signature
特点会坚持类签名信息,而 TypeToken
仅仅一个东西类,内部经过反射获取类签名中泛型信息并回来 Type
类型。
TypeToken.java
protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode();
}
// 回来 Response<User>
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]);
}
public final Type getType() {
return type;
}
已然 TypeToken 仅仅一个获取 Type 类型的东西类,咱们也能够跳过它直接供给 Type,办法是定义 ParameterizedType
参数化类型的子类:
ParameterizedTypeAdapter.java
private static class ParameterizedTypeAdapter implements ParameterizedType {
private final Class<?> rawType;
private final Type[] types;
private ParameterizedTypeAdapter(Class<?> rawType, Type... types) {
this.rawType = rawType;
this.types = types;
}
@Override
public Type[] getActualTypeArguments() {
return types;
}
@Override
public Type getRawType() {
return rawType;
}
@Override
public Type getOwnerType() {
return null;
}
}
示例代码
Response<User> obj = new Gson().fromJson<Response<User>>(jsonStr, ParameterizedTypeAdapter(Response.class, User.class))
在 Kotlin 中,还能够运用 reified 实化类型参数简化:
Utils.kt
inline fun <reified T> toList(jsonStr: String): List<T> =
Gson().fromJson(content, ParameterizedTypeAdapter(List::class.java, T::class.java))
inline fun <reified T> toObject(jsonStr: String): List<T> =
Gson().fromJson(content, T::class.java))
示例代码
List<User> obj = toList<User>(jsonStr)
4. 总结
今天,咱们评论了 Gson 的根本用法和以及主要流程的源码剖析。
在 Gson 的反序列化中,初次反序列化一个类型的目标时,Gson 需求运用大量反射调用解析一个 TypeAdapter 适配器目标。随着 Model 的复杂程度添加,初次解析的耗时会不断膨胀。
这个问题在抖音的技能博客中提到一个处理方案,这个问题咱们鄙人篇文章评论,请关注。
版权声明
本文为稀土技能社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!
参考资料
- Java Google Json (Gson) Introduction —— Mithil Shah 著
- Gson — Getting Started with Java-JSON —— Norman Peitek 著
- Javadoc Gson —— Gson 官方文档
- Gson 源码解析和它的规划形式 —— 拉丁吴 著
- 还在被数据类的序列化折磨?是时分丢掉 Gson 了—— bennyhuo 著
- 抖音 Android 功能优化系列:启动优化实践(反序列化优化) —— 字节跳动技能团队 著
- JSON —— Wikipedia