Android Gson JsonTreeBasedAdapter:基于JsonTree的灵活适配的原理(12)

56 阅读11分钟

码字不易,请大佬们点点关注,谢谢~

一、JsonTreeBasedAdapter概述

1.1 在Gson中的角色定位

JsonTreeBasedAdapter是Gson库中用于实现基于JSON树模型(JsonElement)的序列化和反序列化的适配器。它作为TypeAdapter的一种具体实现,为那些需要灵活处理JSON结构的场景提供了强大支持。

与直接操作JsonReader和JsonWriter的TypeAdapter不同,JsonTreeBasedAdapter通过将JSON数据转换为中间的树模型(由JsonElement及其子类组成),再进行处理。这种方式虽然在性能上可能略逊一筹,但提供了更高的灵活性,尤其适合处理结构复杂或动态变化的JSON数据。

1.2 与其他适配器的关系

Gson中的适配器体系主要包括以下几种类型:

  1. 直接操作流的适配器:直接通过JsonReader和JsonWriter读写JSON数据,性能最优。
  2. 基于JsonTree的适配器:将JSON转换为树模型处理,提供更高的灵活性。
  3. 反射式适配器:通过Java反射自动处理普通Java对象。

JsonTreeBasedAdapter属于第二类,它在内部使用JsonSerializer和JsonDeserializer来处理JSON树模型:

// JsonTreeBasedAdapter类的定义
public final class JsonTreeBasedAdapter<T> extends TypeAdapter<T> {
    private final JsonSerializer<T> serializer; // JSON序列化器
    private final JsonDeserializer<T> deserializer; // JSON反序列化器
    private final Gson gson; // Gson实例
    private final TypeToken<T> typeToken; // 类型令牌
    
    // 构造函数
    public JsonTreeBasedAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
            Gson gson, TypeToken<T> typeToken) {
        this.serializer = serializer;
        this.deserializer = deserializer;
        this.gson = gson;
        this.typeToken = typeToken;
    }
    
    // 实现TypeAdapter的write方法
    @Override public void write(JsonWriter out, T value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        
        // 使用JsonSerializer将对象转换为JsonElement
        JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext());
        
        // 将JsonElement写入JsonWriter
        Streams.write(tree, out);
    }
    
    // 实现TypeAdapter的read方法
    @Override public T read(JsonReader in) throws IOException {
        // 从JsonReader读取并解析为JsonElement
        JsonElement tree = Streams.parse(in);
        
        if (tree.isJsonNull()) {
            return null;
        }
        
        // 使用JsonDeserializer将JsonElement转换为对象
        return deserializer.deserialize(tree, typeToken.getType(), gson.deserializationContext());
    }
}

1.3 适用场景

JsonTreeBasedAdapter适用于以下场景:

  1. 动态JSON结构:当JSON结构不固定,需要在运行时动态处理时。
  2. 复杂转换逻辑:当序列化或反序列化逻辑复杂,需要完整的JSON树结构支持时。
  3. 与现有代码集成:当需要与使用JsonElement API的现有代码集成时。
  4. 自定义注解处理:当需要根据自定义注解调整序列化或反序列化行为时。

二、JSON树模型核心类结构

2.1 JsonElement层次结构

Gson的JSON树模型由JsonElement抽象类及其子类组成,主要包括:

  1. JsonPrimitive:表示基本类型值(字符串、数字、布尔值等)
  2. JsonArray:表示JSON数组
  3. JsonObject:表示JSON对象
  4. JsonNull:表示JSON null值

这些类的关系如下:

// JsonElement抽象类
public abstract class JsonElement implements Cloneable {
    // 判断是否为JsonPrimitive
    public boolean isJsonPrimitive() {
        return this instanceof JsonPrimitive;
    }
    
    // 判断是否为JsonArray
    public boolean isJsonArray() {
        return this instanceof JsonArray;
    }
    
    // 判断是否为JsonObject
    public boolean isJsonObject() {
        return this instanceof JsonObject;
    }
    
    // 判断是否为JsonNull
    public boolean isJsonNull() {
        return this instanceof JsonNull;
    }
    
    // 转换为JsonPrimitive
    public JsonPrimitive getAsJsonPrimitive() {
        return (JsonPrimitive) this;
    }
    
    // 转换为JsonArray
    public JsonArray getAsJsonArray() {
        return (JsonArray) this;
    }
    
    // 转换为JsonObject
    public JsonObject getAsJsonObject() {
        return (JsonObject) this;
    }
    
    // 其他方法...
}

// JsonPrimitive类
public final class JsonPrimitive extends JsonElement {
    private final Object value; // 存储基本类型值
    
    // 构造函数
    public JsonPrimitive(Boolean value) {
        this.value = Preconditions.checkNotNull(value);
    }
    
    public JsonPrimitive(Number value) {
        this.value = Preconditions.checkNotNull(value);
    }
    
    public JsonPrimitive(String value) {
        this.value = Preconditions.checkNotNull(value);
    }
    
    // 获取各种类型的值
    public boolean getAsBoolean() {
        if (isBoolean()) {
            return ((Boolean) value).booleanValue();
        }
        // 其他类型转换逻辑...
    }
    
    public Number getAsNumber() {
        if (isNumber()) {
            return (Number) value;
        }
        // 其他类型转换逻辑...
    }
    
    public String getAsString() {
        if (isString()) {
            return (String) value;
        }
        // 其他类型转换逻辑...
    }
    
    // 其他方法...
}

// JsonArray类
public final class JsonArray extends JsonElement implements Iterable<JsonElement> {
    private final List<JsonElement> elements; // 存储数组元素
    
    // 构造函数
    public JsonArray() {
        this.elements = new ArrayList<>();
    }
    
    // 添加元素
    public void add(JsonElement element) {
        elements.add(element == null ? JsonNull.INSTANCE : element);
    }
    
    // 获取元素
    public JsonElement get(int index) {
        return elements.get(index);
    }
    
    // 获取元素数量
    public int size() {
        return elements.size();
    }
    
    // 实现Iterable接口
    @Override
    public Iterator<JsonElement> iterator() {
        return elements.iterator();
    }
    
    // 其他方法...
}

// JsonObject类
public final class JsonObject extends JsonElement {
    private final LinkedTreeMap<String, JsonElement> members; // 存储对象成员
    
    // 构造函数
    public JsonObject() {
        this.members = new LinkedTreeMap<>();
    }
    
    // 添加成员
    public void add(String property, JsonElement value) {
        if (value == null) {
            value = JsonNull.INSTANCE;
        }
        members.put(property, value);
    }
    
    // 获取成员
    public JsonElement get(String property) {
        return members.get(property);
    }
    
    // 获取所有成员名
    public Set<String> keySet() {
        return members.keySet();
    }
    
    // 获取所有成员
    public Set<Map.Entry<String, JsonElement>> entrySet() {
        return members.entrySet();
    }
    
    // 其他方法...
}

// JsonNull类
public final class JsonNull extends JsonElement {
    // 单例实现
    public static final JsonNull INSTANCE = new JsonNull();
    
    private JsonNull() {}
    
    @Override
    public int hashCode() {
        return JsonNull.class.hashCode();
    }
    
    @Override
    public boolean equals(Object obj) {
        return this == obj || obj instanceof JsonNull;
    }
}

2.2 JsonSerializer接口

JsonSerializer接口用于将Java对象序列化为JsonElement:

public interface JsonSerializer<T> {
    /**
     * 将Java对象序列化为JsonElement
     * 
     * @param src 待序列化的对象
     * @param typeOfSrc 对象的类型
     * @param context 序列化上下文,可用于序列化对象的字段
     * @return 序列化后的JsonElement
     */
    public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
}

2.3 JsonDeserializer接口

JsonDeserializer接口用于将JsonElement反序列化为Java对象:

public interface JsonDeserializer<T> {
    /**
     * 将JsonElement反序列化为Java对象
     * 
     * @param json 待反序列化的JsonElement
     * @param typeOfT 对象的类型
     * @param context 反序列化上下文,可用于反序列化对象的字段
     * @return 反序列化后的Java对象
     * @throws JsonParseException 如果解析失败
     */
    public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException;
}

三、JsonTreeBasedAdapter源码解析

3.1 类定义与成员变量

public final class JsonTreeBasedAdapter<T> extends TypeAdapter<T> {
    private final JsonSerializer<T> serializer; // JSON序列化器
    private final JsonDeserializer<T> deserializer; // JSON反序列化器
    private final Gson gson; // Gson实例
    private final TypeToken<T> typeToken; // 类型令牌
    
    // 构造函数
    public JsonTreeBasedAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
            Gson gson, TypeToken<T> typeToken) {
        this.serializer = serializer;
        this.deserializer = deserializer;
        this.gson = gson;
        this.typeToken = typeToken;
    }
}

3.2 序列化流程

JsonTreeBasedAdapter的序列化流程通过write方法实现:

@Override public void write(JsonWriter out, T value) throws IOException {
    if (value == null) {
        out.nullValue(); // 如果值为null,直接写入null
        return;
    }
    
    // 使用JsonSerializer将对象转换为JsonElement
    JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext());
    
    // 将JsonElement写入JsonWriter
    Streams.write(tree, out);
}

其中,Streams.write方法的实现如下:

public final class Streams {
    /**
     * 将JsonElement写入JsonWriter
     */
    public static void write(JsonElement element, JsonWriter writer) throws IOException {
        // 处理null值
        if (element.isJsonNull()) {
            writer.nullValue();
            return;
        }
        
        // 处理布尔值
        if (element.isJsonPrimitive()) {
            JsonPrimitive primitive = element.getAsJsonPrimitive();
            if (primitive.isBoolean()) {
                writer.value(primitive.getAsBoolean());
                return;
            }
            
            // 处理数字
            if (primitive.isNumber()) {
                writer.value(primitive.getAsNumber());
                return;
            }
            
            // 处理字符串
            if (primitive.isString()) {
                writer.value(primitive.getAsString());
                return;
            }
            
            throw new AssertionError();
        }
        
        // 处理数组
        if (element.isJsonArray()) {
            writer.beginArray();
            for (JsonElement e : element.getAsJsonArray()) {
                write(e, writer);
            }
            writer.endArray();
            return;
        }
        
        // 处理对象
        if (element.isJsonObject()) {
            writer.beginObject();
            for (Map.Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) {
                writer.name(entry.getKey());
                write(entry.getValue(), writer);
            }
            writer.endObject();
            return;
        }
        
        throw new AssertionError();
    }
}

3.3 反序列化流程

JsonTreeBasedAdapter的反序列化流程通过read方法实现:

@Override public T read(JsonReader in) throws IOException {
    // 从JsonReader读取并解析为JsonElement
    JsonElement tree = Streams.parse(in);
    
    if (tree.isJsonNull()) {
        return null; // 如果是null值,直接返回null
    }
    
    // 使用JsonDeserializer将JsonElement转换为对象
    return deserializer.deserialize(tree, typeToken.getType(), gson.deserializationContext());
}

其中,Streams.parse方法的实现如下:

public final class Streams {
    /**
     * 从JsonReader解析出JsonElement
     */
    public static JsonElement parse(JsonReader reader) throws JsonParseException {
        boolean isEmpty = true;
        try {
            reader.peek();
            isEmpty = false;
            return parse(reader, false);
        } catch (EOFException e) {
            /*
             * For compatibility with JSON 1.5 and earlier, we return a JsonNull for empty
             * documents instead of throwing.
             */
            if (isEmpty) {
                return JsonNull.INSTANCE;
            }
            // The stream ended prematurely so it is likely a syntax error.
            throw new JsonSyntaxException(e);
        } catch (IllegalStateException e) {
            throw new JsonSyntaxException(e);
        } catch (IOException e) {
            throw new JsonIOException(e);
        }
    }
    
    private static JsonElement parse(JsonReader reader, boolean lenient) throws IOException {
        JsonToken token = reader.peek();
        
        switch (token) {
            case BEGIN_ARRAY:
                return parseArray(reader, lenient);
            case BEGIN_OBJECT:
                return parseObject(reader, lenient);
            case STRING:
                return new JsonPrimitive(reader.nextString());
            case NUMBER:
                String number = reader.nextString();
                // 尝试将数字解析为合适的类型
                try {
                    return new JsonPrimitive(Long.parseLong(number));
                } catch (NumberFormatException e) {
                    try {
                        return new JsonPrimitive(Double.parseDouble(number));
                    } catch (NumberFormatException e2) {
                        return new JsonPrimitive(number);
                    }
                }
            case BOOLEAN:
                return new JsonPrimitive(reader.nextBoolean());
            case NULL:
                reader.nextNull();
                return JsonNull.INSTANCE;
            case END_DOCUMENT:
            case NAME:
            case END_OBJECT:
            case END_ARRAY:
                throw new JsonSyntaxException("Unexpected token: " + token);
            default:
                throw new AssertionError();
        }
    }
    
    // 解析JSON数组
    private static JsonArray parseArray(JsonReader reader, boolean lenient) throws IOException {
        JsonArray array = new JsonArray();
        reader.beginArray();
        while (reader.hasNext()) {
            array.add(parse(reader, lenient));
        }
        reader.endArray();
        return array;
    }
    
    // 解析JSON对象
    private static JsonObject parseObject(JsonReader reader, boolean lenient) throws IOException {
        JsonObject object = new JsonObject();
        reader.beginObject();
        while (reader.hasNext()) {
            String name = reader.nextName();
            object.add(name, parse(reader, lenient));
        }
        reader.endObject();
        return object;
    }
}

四、JsonSerializationContext与JsonDeserializationContext

4.1 序列化上下文

JsonSerializationContext接口提供了在序列化过程中处理对象字段的能力:

public interface JsonSerializationContext {
    /**
     * 将对象序列化为JsonElement
     * 
     * @param src 待序列化的对象
     * @return 序列化后的JsonElement
     */
    public JsonElement serialize(Object src);
    
    /**
     * 将对象序列化为JsonElement,指定类型
     * 
     * @param src 待序列化的对象
     * @param typeOfSrc 对象的类型
     * @return 序列化后的JsonElement
     */
    public JsonElement serialize(Object src, Type typeOfSrc);
}

Gson中的默认实现类是SerializationContext:

final class SerializationContext implements JsonSerializationContext {
    private final Gson gson;
    
    SerializationContext(Gson gson) {
        this.gson = gson;
    }
    
    @Override
    public JsonElement serialize(Object src) {
        if (src == null) {
            return JsonNull.INSTANCE;
        }
        
        // 获取对象的实际类型
        Type type = $Gson$Types.getRawType(src.getClass());
        
        // 委托给Gson的toJsonTree方法
        return gson.toJsonTree(src, type);
    }
    
    @Override
    public JsonElement serialize(Object src, Type typeOfSrc) {
        if (src == null) {
            return JsonNull.INSTANCE;
        }
        
        // 委托给Gson的toJsonTree方法
        return gson.toJsonTree(src, typeOfSrc);
    }
}

4.2 反序列化上下文

JsonDeserializationContext接口提供了在反序列化过程中处理对象字段的能力:

public interface JsonDeserializationContext {
    /**
     * 将JsonElement反序列化为指定类型的对象
     * 
     * @param json 待反序列化的JsonElement
     * @param typeOfT 对象的类型
     * @return 反序列化后的对象
     * @throws JsonParseException 如果解析失败
     */
    public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;
}

Gson中的默认实现类是DeserializationContext:

final class DeserializationContext implements JsonDeserializationContext {
    private final Gson gson;
    private final Stack<Type> stack;
    
    DeserializationContext(Gson gson, Stack<Type> stack) {
        this.gson = gson;
        this.stack = stack;
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
        if (json == null) {
            return null;
        }
        
        // 检查循环引用
        if (stack.contains(typeOfT)) {
            throw new JsonParseException("Circular reference detected");
        }
        
        try {
            // 将当前类型压入栈中
            stack.push(typeOfT);
            
            // 委托给Gson的fromJsonTree方法
            return (T) gson.fromJsonTree(json, typeOfT);
        } finally {
            // 从栈中弹出当前类型
            stack.pop();
        }
    }
}

五、实际应用案例

5.1 处理动态JSON结构

假设我们需要处理一个动态的JSON结构,其中某个字段的类型可能是字符串或对象:

{
    "name": "John",
    "data": "simple value"
}

{
    "name": "Jane",
    "data": {
        "key1": "value1",
        "key2": "value2"
    }
}

我们可以使用JsonTreeBasedAdapter来处理这种情况:

class DynamicDataAdapter implements JsonDeserializer<Object>, JsonSerializer<Object> {
    @Override
    public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        if (json.isJsonPrimitive()) {
            // 如果是基本类型,直接返回字符串值
            return json.getAsString();
        } else if (json.isJsonObject()) {
            // 如果是对象,转换为Map
            Map<String, Object> map = new LinkedHashMap<>();
            JsonObject jsonObject = json.getAsJsonObject();
            
            for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
                // 递归处理每个字段
                map.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class));
            }
            
            return map;
        } else if (json.isJsonArray()) {
            // 如果是数组,转换为List
            List<Object> list = new ArrayList<>();
            JsonArray jsonArray = json.getAsJsonArray();
            
            for (JsonElement element : jsonArray) {
                // 递归处理每个元素
                list.add(context.deserialize(element, Object.class));
            }
            
            return list;
        } else {
            return null;
        }
    }
    
    @Override
    public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContext context) {
        if (src == null) {
            return JsonNull.INSTANCE;
        }
        
        if (src instanceof String) {
            return new JsonPrimitive((String) src);
        } else if (src instanceof Number) {
            return new JsonPrimitive((Number) src);
        } else if (src instanceof Boolean) {
            return new JsonPrimitive((Boolean) src);
        } else if (src instanceof Map) {
            // 处理Map
            JsonObject jsonObject = new JsonObject();
            Map<?, ?> map = (Map<?, ?>) src;
            
            for (Map.Entry<?, ?> entry : map.entrySet()) {
                // 递归处理每个键值对
                String key = String.valueOf(entry.getKey());
                jsonObject.add(key, context.serialize(entry.getValue()));
            }
            
            return jsonObject;
        } else if (src instanceof Collection) {
            // 处理Collection
            JsonArray jsonArray = new JsonArray();
            Collection<?> collection = (Collection<?>) src;
            
            for (Object element : collection) {
                // 递归处理每个元素
                jsonArray.add(context.serialize(element));
            }
            
            return jsonArray;
        } else if (src.getClass().isArray()) {
            // 处理数组
            JsonArray jsonArray = new JsonArray();
            int length = java.lang.reflect.Array.getLength(src);
            
            for (int i = 0; i < length; i++) {
                // 递归处理每个元素
                jsonArray.add(context.serialize(java.lang.reflect.Array.get(src, i)));
            }
            
            return jsonArray;
        } else {
            // 其他对象类型,使用默认序列化
            return context.serialize(src);
        }
    }
}

5.2 自定义注解处理

假设我们有一个自定义注解@Encrypt,用于标记需要加密的字段:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Encrypt {
}

我们可以创建一个适配器来处理这个注解:

class EncryptedFieldAdapter implements JsonSerializer<Object>, JsonDeserializer<Object> {
    private final Cipher encryptCipher;
    private final Cipher decryptCipher;
    
    public EncryptedFieldAdapter() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
        // 初始化加密和解密的Cipher
        SecretKeySpec secretKey = new SecretKeySpec("MySecretKey12345".getBytes(), "AES");
        encryptCipher = Cipher.getInstance("AES");
        encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey);
        
        decryptCipher = Cipher.getInstance("AES");
        decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
    }
    
    @Override
    public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContext context) {
        if (src == null) {
            return JsonNull.INSTANCE;
        }
        
        try {
            // 将对象转换为字符串
            String plainText = src.toString();
            
            // 加密字符串
            byte[] encryptedBytes = encryptCipher.doFinal(plainText.getBytes());
            
            // 将加密后的字节数组转换为Base64编码
            String encryptedString = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
            
            return new JsonPrimitive(encryptedString);
        } catch (Exception e) {
            throw new JsonParseException("Encryption error", e);
        }
    }
    
    @Override
    public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        if (json.isJsonNull()) {
            return null;
        }
        
        try {
            // 获取加密的字符串
            String encryptedString = json.getAsString();
            
            // 将Base64编码的字符串转换为字节数组
            byte[] encryptedBytes = Base64.decode(encryptedString, Base64.DEFAULT);
            
            // 解密字节数组
            byte[] decryptedBytes = decryptCipher.doFinal(encryptedBytes);
            
            // 转换为原始类型
            String plainText = new String(decryptedBytes);
            
            // 根据目标类型进行转换
            if (typeOfT == String.class) {
                return plainText;
            } else if (typeOfT == Integer.class || typeOfT == int.class) {
                return Integer.parseInt(plainText);
            } else if (typeOfT == Long.class || typeOfT == long.class) {
                return Long.parseLong(plainText);
            } else {
                // 对于其他类型,尝试使用默认反序列化
                return context.deserialize(json, typeOfT);
            }
        } catch (Exception e) {
            throw new JsonParseException("Decryption error", e);
        }
    }
}

六、性能分析与优化

6.1 性能特点

基于JsonTree的适配器相比直接操作流的适配器有以下性能特点:

  1. 内存开销:需要构建完整的JSON树模型,内存占用较高。
  2. 处理速度:由于需要两次处理(先构建树,再处理树),处理速度较慢。
  3. 灵活性:提供了更高的灵活性,可以在处理过程中修改JSON结构。

6.2 性能优化建议

  1. 避免不必要的树模型:对于结构简单且固定的JSON,优先使用直接操作流的适配器。
  2. 缓存常用转换逻辑:对于复杂的转换逻辑,考虑缓存中间结果以提高性能。
  3. 批量处理:在处理大量数据时,考虑批量处理以减少对象创建开销。
  4. 选择合适的数据结构:在处理大型JSON时,选择高效的数据结构存储中间结果。

七、总结与展望

7.1 JsonTreeBasedAdapter的优势

JsonTreeBasedAdapter作为Gson中基于JSON树模型的适配器,具有以下优势:

  1. 灵活性:能够处理动态变化的JSON结构,适合复杂场景。
  2. 易于实现:相比直接操作流的适配器,基于树模型的实现更直观。
  3. 完整访问:可以完全访问和修改JSON结构,适合需要深度处理的场景。
  4. 与现有代码集成:便于与使用JsonElement API的现有代码集成。

7.2 未来发展方向

随着JSON处理需求的不断变化,JsonTreeBasedAdapter可能会在以下方向发展:

  1. 性能优化:通过改进树模型的实现和处理算法,提高性能。
  2. 异步支持:提供对异步处理的支持,适应现代应用的需求。
  3. Kotlin协程集成:更好地支持Kotlin协程,简化异步处理逻辑。
  4. 与其他框架集成:更紧密地集成其他Android和Java框架,提供更统一的API。
  5. 减少内存占用:优化树模型的内存使用,降低资源消耗。

通过不断优化和扩展,JsonTreeBasedAdapter将继续作为Gson的重要组成部分,为开发者提供灵活、高效的JSON处理解决方案。