Android serialization framework Gson principle analysis, can it be optimized?

This article has included AndroidFamily , technical and workplace issues, please pay attention to the public account [Peng Xurui] to ask questions.

foreword

Hello everyone, I am Xiao Peng.

Gson is a Java Json parsing library launched by Google. It has the advantages of low access cost, convenient use, and good function scalability. Everyone must be familiar with it. In this article, we will discuss the basic usage of Gson and the source code analysis of the main process.


Xiaopeng's Android communication group 02 has been established, scan the QR code at the end of the article to enter~


Learning Roadmap:


1. Basic usage of Gson

Gradle 依赖

dependencies {
    
    
    implementation 'com.google.code.gson:gson:2.10'
}

1.1 GsonBuilder configuration items

The Gson class is the core API of the entire library, and before any serialization or deserialization, we need to obtain a Gson object. You can directly create a default configured Gson object with new, or use the GsonBuilder constructor to configure a Gson object.

In fact, a Gson object represents a Gson working environment, and configurations and caches between different Gson objects will not be reused. Therefore, it is necessary to provide a global Gson object in the common layer in the project, which is not only conducive to unified serialization configuration, but also the basic guarantee for Gson performance optimization.

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 Annotation configuration

Gson has no compile-time processing, so annotations are runtime annotations.

  • @SerializedName field alias: supports setting multiple aliases, valuevariables are valid during serialization and deserialization, and alternatevariables only compatible during deserialization;
  • @Expose fields are exposed:
    • By default, all fields in a class will be exposed, but after using the @Expose annotation, only the fields that declare the annotation will be exposed;
    • Annotated serializevariables or deserializevariables can declare that fields only participate in serialization or deserialization, and both participate by default.
  • @JsonAdapter annotation: declared on a specific class or field, used to set TypeAdapter in a more granular manner, with a higher priority than registerTypeAdapter;
  • @Since annotation: Declare on a specific class or field, declare the initial serialized version of the field;
  • @Until annotation: Declared on a concrete class or field, declares the terminated serialized version of the field. When the serialized version of the field satisfies since ≥ GsonBuilder#setVersion and GsonBuilder#setVersion ≤ until, it will participate in serialization;

1.3 JsonSerializer and JsonDeserializer custom parsing

JsonSerializerand JsonDeserializerare custom parsing APIs provided by Gson version 1.x, which are tree-based parsing APIs. When parsing data, they will parse Json data into a JsonElementtree . JsonElement represents a node on the Json tree, and has 4 specific types:

JsonElement describe
JsonObject {} object
JsonArray [] array
JsonPrimitive basic type
JsonNull null value

1.4 TypeAdapter custom analysis

TypeAdapterIt is a new custom parsing API added by Gson 2.0, and it is an API based on a streaming structure. In fact, JsonSerializer and JsonDeserializer will also end up being constructed as TreeTypeAdapter;

In comparison, JsonSerializer & JsonDeserializer are relatively convenient, but more memory-intensive. The TypeAdapter is more memory-efficient, but less convenient. However, if you need to use a complete data structure (such as parsing data according to different types according to the type field), you can also manually parse it into a tree structure. Therefore, the TypeAdapter API has a higher priority.

TypeAdapter JsonSerializer、JsonDeserializer
import version 2.0 1.x
Stream API support not support
Tree API Support, can be converted manually support
memory usage Small Larger than TypeAdapter
efficiency high Lower than TypeAdapter
Scope of action Serialization + deserialization serialization / deserialization

1.5 The difference between registerTypeAdapter and registerTypeHierarchyAdapter

  • registerTypeAdapter is invariant: it will only work on registered types. For example, registration <List.class,TypeAdapter>will only affect the fields of Listthe type , but not the fields of the ArrayList type;
  • registerTypeHierarchyAdapter is covariant: it works on the registered type and its subclasses. For example, registration <List.class,TypeAdapter>will only affect Listfields ArrayListof type ;
registerTypeAdapter registerTypeHierarchyAdapter
supports generics yes no
support inheritance no yes

2. Gson source code analysis

In this section, let's analyze the working principle and source code of Gson's core process.

2.1 Talk about the working process of Gson parsing

"TypeAdapter" is an important role in Gson parsing. Every time Gson parses an object type, it first needs to create a TypeAdapter object, and then all parsing work will be handed over to the TypeAdapter#write and TypeAdapter#read methods;

The TypeAdapter object of the Java Bean type is created by the "ReflectiveTypeAdapterFactory" . Every time you create a type of TypeAdapter, you need to recursively use "reflection" to traverse all fields, and parse the annotations on the fields to generate <serializeName - BoundFiled>a mapping table.

  • When serializing, first use reflection to get the field value, and then use BoundFiledthe serialization ;
  • When deserializing, first create an object instance (how to create it will be discussed below), then use BoundFieldthe deserialization as the value of the field type, and then assign a value to the field through reflection.

Since the writing and reading of field values ​​are performed through Fieldmetadata reflection, private fields can also be manipulated.

When constructing the Gson object, a series of TypeAdapter creation factories have been initialized, and developers can register custom TypeAdapters:

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));
}

Find the matching TypeAdapter method through Gson#getAdapter:

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;
        }
    }
}

Create TypeAdapter objects for each type using the ReflectiveTypeAdapterFactory factory:

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 How are container types such as List & Set & Map parsed?

  • 1. In the preset container TypAdapter, the container constructor will be RawTypeobtained , and then elementTypethe element type TypeAdapter will be obtained according to the generic argument;
  • 2. When serializing, first write [left square brackets, then use the TypeAdapter of the element type to serialize element objects in turn, and then write ] right square brackets;
  • 3. When deserializing, first create a collection object, and then use the TypeAdapter of the element type to deserialize the element objects in turn;
  • 4. The Map type needs to maintain two TypeAdapters, Key and Value.

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 How is the enumerated type parsed?

  • 1. In the preset EnumTypeAdapter adapter, the entire enumeration list of the enumeration type will be obtained first, and two mapping tables will be generated.
    • <name - enumeration> mapping table
    • <enum-name> mapping table
  • 2. When serializing, the name of the enumeration will be written. When deserializing, the enumeration object will be queried according to the 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 Will nesting of the same type cause infinite recursion?

ReflectiveTypeAdapterFactoryWhen creating an object's TypeAdapter adapter, it is necessary to recursively create a TypeAdapter for each field. If the type of the field happens to be the same as the type of the class, it will trigger the creation of an identical TypeAdapter, causing infinite recursion. For example:

无限递归的例子

public class Article {
    
    
    public Article linkedArticle;
}

The analysis found that infinite recursion only occurs when a TypeAdapter of a Java Bean type is created for the first time, and it will be obtained from the cache next time, and infinite recursion will not occur. Therefore, Gson's approach is:

  • 1. Before creating a new TypeAdapter each time, create a FutureTypeAdapterproxy . After creating the real TypeAdapter, inject it into the proxy object. In this way, when recursively obtaining the TypeAdapter of the field, the proxy object will be obtained instead of recreating the TypeAdapter, thus solving the recursion problem;
  • 2. In addition, considering that in a multi-threaded environment, the addition and removal of temporary mapping tables will have concurrency issues, so Gson's strategy is to use temporary mapping tables that ThreadLocalisolate each thread.

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 How does Gson create objects?

  • 1. Basic types: Integer, Calendar and other basic types have a fixed TypeAdapter, which will create objects through the new keyword;
  • 2. Enumeration: The serialization and deserialization of the enumeration is just switching between the enumeration name and the enumeration object, and no new enumeration object will be created;
  • 3. List & Set & Map: The container type will create a factory through a preset object, and call the new keyword to create an object;
  • 4. Java Bean: The creation of Java Bean is divided into many possibilities:
    • Case 1: If the object creation factory is customized InstanceCreator, it is first created through the custom factory;
    • Case 2: If there is a default no-argument constructor, it is created through the reflection constructor;
    • Case 3: Use the Unsafe API to create objects.

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 Hidden Pit

When Class does not provide a default no-argument constructor, Gson will use the Unsafe API to create objects. The Unsafe API mainly provides methods for performing low-level, unsafe operations, and also provides an unconventional allocateInstancemethod .

This API does not call the constructor, so the relevant construction initialization operations will be lost;

  • 1. The default value of the constructor parameter is lost;
  • 2. The default value of the field is lost;
  • 3. Kotlin non-null type is invalid;
  • 4. The initialization block is not executed;
  • 5. By attribute proxy (no proxy object created)

3. How does Gson resolve generic types?

Since Java has generic erasure, it is impossible to directly declare generic information on .classthe grammar . Gson's method is to require programmers to create anonymous inner classes, and Gson can obtain generic information on class declarations through reflection at runtime.

示例代码

// 非法:
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)

Why use anonymous inner classes to deserialize generic classes?

The principle is that Signaturethe attribute will keep the class signature information, and TypeTokenis just a tool class that internally obtains the generic information in the class signature through reflection and returns Typethe 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;
}

Since TypeToken is just a tool class to obtain the Type type, we can also skip it and directly provide the Type by defining ParameterizedTypea subclass of the parameterized type:

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))

In Kotlin, it is also possible to use the reified parameter simplification:

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. Summary

Today, we discussed the basic usage of Gson and the source code analysis of the main process.

In Gson's deserialization, when deserializing a type object for the first time, Gson needs to use a lot of reflection calls to resolve a TypeAdapter adapter object. As the complexity of the Model increases, the time-consuming for the first parsing will continue to expand.

A solution to this problem is mentioned in Douyin’s technical blog. We will discuss this problem in the next article, please pay attention.


References

Xiaopeng's Android communication group 02 group

Guess you like

Origin blog.csdn.net/pengxurui/article/details/128039818