Android Gson ReflectiveTypeAdapterFactory:反射式类型适配的原理(11)

104 阅读11分钟

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

一、ReflectiveTypeAdapterFactory概述

1.1 在Gson中的核心地位

ReflectiveTypeAdapterFactory是Gson库中处理Java对象序列化和反序列化的核心工厂类。它通过Java反射机制,动态分析Java类的字段结构,并基于这些信息创建对应的TypeAdapter,从而实现Java对象与JSON数据之间的自动转换。

在Gson的默认配置中,大部分普通Java对象的序列化和反序列化都是通过ReflectiveTypeAdapterFactory创建的适配器来完成的。因此,深入理解ReflectiveTypeAdapterFactory的工作原理,对于掌握Gson的核心机制至关重要。

1.2 反射式类型适配的优势与局限

反射式类型适配的主要优势在于:

  1. 自动化:无需为每个Java类编写显式的序列化和反序列化代码,Gson会自动处理大多数情况。
  2. 灵活性:支持嵌套对象、集合和数组等复杂数据结构。
  3. 易用性:对于简单的Java Bean,只需少量配置甚至无需配置即可使用。

然而,反射式类型适配也存在一些局限性:

  1. 性能开销:反射操作比直接代码执行慢,尤其是在处理大量对象时。
  2. 访问限制:需要正确设置字段的可访问性,可能受到Java访问修饰符的限制。
  3. 安全性问题:在某些环境下(如Android的ProGuard混淆),反射可能会受到影响。

1.3 与其他TypeAdapterFactory的关系

Gson通过TypeAdapterFactory链来处理不同类型的序列化和反序列化。ReflectiveTypeAdapterFactory是这个链中的重要一环,通常作为最后一个工厂被调用,用于处理那些没有被其他工厂处理的类型。

Gson的默认工厂链顺序大致如下:

  1. 处理@JsonAdapter注解的工厂
  2. 基本类型(如int、String)的工厂
  3. 集合和数组的工厂
  4. 反射式工厂(ReflectiveTypeAdapterFactory)

当需要序列化或反序列化某个类型时,Gson会按顺序遍历工厂链,直到找到一个能够处理该类型的工厂。如果所有工厂都无法处理,则会抛出异常。

二、ReflectiveTypeAdapterFactory的核心结构

2.1 类定义与主要成员变量

ReflectiveTypeAdapterFactory的类定义如下:

public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
    private final ConstructorConstructor constructorConstructor; // 用于创建对象的构造器
    private final FieldNamingStrategy fieldNamingPolicy; // 字段命名策略
    private final Excluder excluder; // 字段排除器
    private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory; // 处理@JsonAdapter注解的工厂
    
    // 内部类:用于表示Java类的字段及其绑定信息
    static abstract class BoundField {
        final String name; // JSON字段名
        final boolean serialized; // 是否序列化
        final boolean deserialized; // 是否反序列化
        
        protected BoundField(String name, boolean serialized, boolean deserialized) {
            this.name = name;
            this.serialized = serialized;
            this.deserialized = deserialized;
        }
        
        // 序列化时写入字段值
        abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
        
        // 反序列化时读取字段值
        abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
        
        // 判断字段是否可空
        abstract boolean writeField(Object value) throws IOException, IllegalAccessException;
    }
    
    // 构造函数
    public ReflectiveTypeAdapterFactory(
        ConstructorConstructor constructorConstructor,
        FieldNamingStrategy fieldNamingPolicy,
        Excluder excluder,
        JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory) {
        this.constructorConstructor = constructorConstructor;
        this.fieldNamingPolicy = fieldNamingPolicy;
        this.excluder = excluder;
        this.jsonAdapterFactory = jsonAdapterFactory;
    }
    
    // 实现TypeAdapterFactory接口的方法,创建TypeAdapter
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        Class<? super T> raw = type.getRawType();
        
        // 检查是否为接口或抽象类
        if (!Object.class.isAssignableFrom(raw)) {
            return null; // 只能处理Object的子类
        }
        
        // 检查是否有@JsonAdapter注解
        JsonAdapter annotation = type.getRawType().getAnnotation(JsonAdapter.class);
        if (annotation != null) {
            // 如果有@JsonAdapter注解,委托给jsonAdapterFactory处理
            return jsonAdapterFactory.create(gson, type, annotation);
        }
        
        // 创建并返回反射式TypeAdapter
        return new Adapter<>(
            constructorConstructor.get(type),
            getBoundFields(gson, type, raw)
        );
    }
    
    // 内部类:反射式TypeAdapter的实现
    static final class Adapter<T> extends TypeAdapter<T> {
        private final ObjectConstructor<T> constructor; // 对象构造器
        private final Map<String, BoundField> boundFields; // 绑定的字段
        
        Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
            this.constructor = constructor;
            this.boundFields = boundFields;
        }
        
        // 序列化方法
        @Override
        public void write(JsonWriter out, T value) throws IOException {
            if (value == null) {
                out.nullValue();
                return;
            }
            
            out.beginObject();
            try {
                for (BoundField boundField : boundFields.values()) {
                    if (boundField.writeField(value)) {
                        out.name(boundField.name);
                        boundField.write(out, value);
                    }
                }
            } catch (IllegalAccessException e) {
                throw new AssertionError(e);
            }
            out.endObject();
        }
        
        // 反序列化方法
        @Override
        public T read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return null;
            }
            
            // 创建实例
            T instance = constructor.construct();
            
            try {
                in.beginObject();
                while (in.hasNext()) {
                    // 读取JSON字段名
                    String name = in.nextName();
                    
                    // 查找匹配的BoundField
                    BoundField field = boundFields.get(name);
                    
                    if (field == null || !field.deserialized) {
                        // 如果没有找到匹配的字段或字段不可反序列化,则跳过
                        in.skipValue();
                    } else {
                        // 读取字段值
                        field.read(in, instance);
                    }
                }
                in.endObject();
            } catch (IllegalStateException e) {
                throw new JsonSyntaxException(e);
            } catch (IllegalAccessException e) {
                throw new AssertionError(e);
            }
            
            return instance;
        }
    }
    
    // 获取绑定字段的方法
    private Map<String, BoundField> getBoundFields(
        Gson context, TypeToken<?> type, Class<?> raw) {
        // 实现逻辑...
    }
}

2.2 关键组件解析

2.2.1 ConstructorConstructor

ConstructorConstructor是一个工厂类,用于创建对象的构造器。它提供了多种方式来实例化对象,包括:

  1. 使用无参构造函数
  2. 使用默认构造函数
  3. 使用Unsafe.allocateInstance(在无构造函数可用时)
  4. 使用自定义的实例创建策略
public final class ConstructorConstructor {
    private final Map<Type, InstanceCreator<?>> instanceCreators;
    
    // 获取对象构造器
    public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
        final Type type = typeToken.getType();
        final Class<? super T> rawType = typeToken.getRawType();
        
        // 尝试使用InstanceCreator
        InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreators.get(type);
        if (creator != null) {
            return new ObjectConstructor<T>() {
                @Override
                public T construct() {
                    return creator.createInstance(type);
                }
            };
        }
        
        // 尝试使用针对原始类型的构造器
        creator = (InstanceCreator<T>) instanceCreators.get(rawType);
        if (creator != null) {
            return new ObjectConstructor<T>() {
                @Override
                public T construct() {
                    return creator.createInstance(type);
                }
            };
        }
        
        // 尝试创建无参构造函数的构造器
        ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
        if (defaultConstructor != null) {
            return defaultConstructor;
        }
        
        // 尝试创建默认构造函数的构造器
        ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
        if (defaultImplementation != null) {
            return defaultImplementation;
        }
        
        // 使用Unsafe.allocateInstance
        return newUnsafeAllocator(type, rawType);
    }
    
    // 其他方法...
}
2.2.2 FieldNamingStrategy

FieldNamingStrategy是一个接口,用于定义Java字段名到JSON字段名的映射策略。Gson提供了多种内置实现:

public interface FieldNamingStrategy {
    // 将Java字段转换为JSON字段名
    public String translateName(Field f);
}

// 内置实现示例
public enum FieldNamingPolicy implements FieldNamingStrategy {
    // 使用原始字段名
    IDENTITY {
        @Override public String translateName(Field f) {
            return f.getName();
        }
    },
    
    // 将字段名转换为小写,并用下划线分隔
    LOWER_CASE_WITH_UNDERSCORES {
        @Override public String translateName(Field f) {
            return lowerCaseWithUnderscores(f.getName());
        }
        
        private String lowerCaseWithUnderscores(String s) {
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (Character.isUpperCase(c)) {
                    if (i > 0) {
                        result.append('_');
                    }
                    result.append(Character.toLowerCase(c));
                } else {
                    result.append(c);
                }
            }
            return result.toString();
        }
    },
    
    // 其他策略...
}
2.2.3 Excluder

Excluder是一个用于排除字段的组件,它根据各种规则决定哪些字段应该被序列化或反序列化。

public final class Excluder implements ExclusionStrategy, Cloneable {
    private double version = -1; // 版本号
    private int modifiers = Modifier.TRANSIENT | Modifier.STATIC; // 要排除的修饰符
    private boolean serializeInnerClasses = true; // 是否序列化内部类
    private boolean requireExpose; // 是否需要@Expose注解
    private final List<ExclusionStrategy> serializationStrategies = new ArrayList<>(); // 序列化排除策略
    private final List<ExclusionStrategy> deserializationStrategies = new ArrayList<>(); // 反序列化排除策略
    
    // 检查字段是否应该被排除
    @Override
    public boolean excludeField(Field field, boolean serialize) {
        // 检查字段修饰符
        if ((field.getModifiers() & modifiers) != 0) {
            return true;
        }
        
        // 检查是否为内部类
        if (!serializeInnerClasses && isInnerClass(field.getType())) {
            return true;
        }
        
        // 检查是否为匿名类或本地类
        if (isAnonymousOrLocal(field.getType())) {
            return true;
        }
        
        // 检查版本控制注解
        if (version != -1) {
            Since since = field.getAnnotation(Since.class);
            if (since != null && since.value() > version) {
                return true;
            }
            Until until = field.getAnnotation(Until.class);
            if (until != null && until.value() <= version) {
                return true;
            }
        }
        
        // 检查@Expose注解
        if (requireExpose) {
            Expose expose = field.getAnnotation(Expose.class);
            if (expose == null) {
                return true;
            }
            if (serialize ? !expose.serialize() : !expose.deserialize()) {
                return true;
            }
        }
        
        // 应用注册的排除策略
        List<ExclusionStrategy> list = serialize
            ? serializationStrategies
            : deserializationStrategies;
        for (ExclusionStrategy exclusionStrategy : list) {
            if (exclusionStrategy.shouldSkipField(fieldAttributes(field))) {
                return true;
            }
        }
        
        return false;
    }
    
    // 其他方法...
}

三、反射式类型适配的工作流程

3.1 适配器的创建过程

当Gson需要序列化或反序列化某个类型时,会调用ReflectiveTypeAdapterFactory的create方法来尝试创建适配器:

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    Class<? super T> raw = type.getRawType();
    
    // 检查是否为接口或抽象类
    if (!Object.class.isAssignableFrom(raw)) {
        return null; // 只能处理Object的子类
    }
    
    // 检查是否有@JsonAdapter注解
    JsonAdapter annotation = type.getRawType().getAnnotation(JsonAdapter.class);
    if (annotation != null) {
        // 如果有@JsonAdapter注解,委托给jsonAdapterFactory处理
        return jsonAdapterFactory.create(gson, type, annotation);
    }
    
    // 创建并返回反射式TypeAdapter
    return new Adapter<>(
        constructorConstructor.get(type),
        getBoundFields(gson, type, raw)
    );
}

3.2 字段绑定过程

getBoundFields方法是ReflectiveTypeAdapterFactory的核心方法之一,它负责收集类的所有字段并创建对应的BoundField:

private Map<String, BoundField> getBoundFields(
    Gson context, TypeToken<?> type, Class<?> raw) {
    Map<String, BoundField> result = new LinkedHashMap<>();
    if (raw.isInterface()) {
        return result; // 接口没有字段
    }
    
    Type declaredType = type.getType();
    while (raw != Object.class) {
        // 获取类的所有字段
        Field[] fields = raw.getDeclaredFields();
        for (Field field : fields) {
            // 检查字段是否应该被排除
            boolean serialize = !excludeField(field, true);
            boolean deserialize = !excludeField(field, false);
            
            if (!serialize && !deserialize) {
                continue; // 如果既不序列化也不反序列化,则跳过
            }
            
            // 设置字段可访问
            field.setAccessible(true);
            
            // 获取字段的泛型类型
            Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
            
            // 获取字段的JSON名称
            List<String> fieldNames = getFieldNames(field);
            
            // 为字段创建BoundField
            BoundField boundField = createBoundField(
                context, field, fieldNames,
                TypeToken.get(fieldType),
                serialize,
                deserialize
            );
            
            // 将BoundField添加到结果中
            for (String name : fieldNames) {
                BoundField previous = result.put(name, boundField);
                if (previous != null) {
                    throw new IllegalArgumentException(
                        "Duplicate field name '" + name + "'. Found on " +
                        previous.field + " and " + field);
                }
            }
        }
        
        // 处理父类字段
        type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
        raw = type.getRawType();
    }
    
    return result;
}

3.3 序列化过程

当需要将Java对象序列化为JSON时,ReflectiveTypeAdapterFactory创建的适配器会执行以下步骤:

@Override
public void write(JsonWriter out, T value) throws IOException {
    if (value == null) {
        out.nullValue();
        return;
    }
    
    out.beginObject(); // 开始写入JSON对象
    try {
        // 遍历所有绑定的字段
        for (BoundField boundField : boundFields.values()) {
            if (boundField.writeField(value)) {
                // 写入字段名
                out.name(boundField.name);
                // 写入字段值
                boundField.write(out, value);
            }
        }
    } catch (IllegalAccessException e) {
        throw new AssertionError(e);
    }
    out.endObject(); // 结束写入JSON对象
}

3.4 反序列化过程

当需要将JSON数据反序列化为Java对象时,适配器会执行以下步骤:

@Override
public T read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
    }
    
    // 创建实例
    T instance = constructor.construct();
    
    try {
        in.beginObject(); // 开始读取JSON对象
        while (in.hasNext()) {
            // 读取JSON字段名
            String name = in.nextName();
            
            // 查找匹配的BoundField
            BoundField field = boundFields.get(name);
            
            if (field == null || !field.deserialized) {
                // 如果没有找到匹配的字段或字段不可反序列化,则跳过
                in.skipValue();
            } else {
                // 读取字段值
                field.read(in, instance);
            }
        }
        in.endObject(); // 结束读取JSON对象
    } catch (IllegalStateException e) {
        throw new JsonSyntaxException(e);
    } catch (IllegalAccessException e) {
        throw new AssertionError(e);
    }
    
    return instance;
}

四、SerializedName注解的处理

4.1 注解解析过程

ReflectiveTypeAdapterFactory在处理字段时,会检查字段上是否存在@SerializedName注解,并根据注解的值确定JSON字段名:

// 获取字段的JSON名称
private List<String> getFieldNames(Field field) {
    SerializedName annotation = field.getAnnotation(SerializedName.class);
    if (annotation == null) {
        // 如果没有注解,使用字段命名策略转换的名称
        return Collections.singletonList(fieldNamingPolicy.translateName(field));
    }
    
    // 获取主名称
    String serializedName = annotation.value();
    // 获取备选名称
    String[] alternates = annotation.alternate();
    
    // 构建名称列表(主名称在前,备选名称在后)
    List<String> fieldNames = new ArrayList<>(1 + alternates.length);
    fieldNames.add(serializedName);
    Collections.addAll(fieldNames, alternates);
    
    return fieldNames;
}

4.2 备选名称的处理

@SerializedName注解的alternate属性允许指定多个备选名称。在反序列化时,Gson会尝试所有可能的名称来匹配JSON字段:

// 将所有名称(主名称和备选名称)都映射到同一个BoundField
for (String name : fieldNames) {
    BoundField previous = result.put(name, boundField);
    if (previous != null) {
        throw new IllegalArgumentException(
            "Duplicate field name '" + name + "'. Found on " +
            previous.field + " and " + field);
    }
}

五、性能优化与挑战

5.1 反射性能开销

反射式类型适配的主要性能开销来自以下几个方面:

  1. 字段查找:通过反射获取类的字段信息需要消耗一定时间。
  2. 访问权限设置:设置字段的可访问性(setAccessible(true))也有一定开销。
  3. 字段值读写:通过反射读写字段值比直接访问慢。

5.2 性能优化策略

Gson采取了多种策略来优化反射性能:

  1. 缓存反射结果:ReflectiveTypeAdapterFactory在初始化时一次性获取所有字段信息,并创建对应的BoundField,后续操作直接使用缓存结果。

  2. 预生成适配器:在某些情况下,Gson可以预生成反射代码,避免运行时反射。

  3. 使用Unsafe:在无构造函数可用时,使用sun.misc.Unsafe.allocateInstance创建对象,避免调用构造函数的开销。

5.3 与直接编码的性能对比

与手动编写的序列化和反序列化代码相比,反射式类型适配通常会慢一些。但在大多数情况下,这种性能差异并不显著,除非是在性能敏感的场景下(如处理大量数据)。

以下是一个简单的性能测试对比(数据仅作示例,实际结果可能因环境而异):

操作类型反射式适配 (ms)手动编码 (ms)性能差异
序列化 10000 个对象8552~63%
反序列化 10000 个对象9261~51%

六、高级应用与扩展

6.1 自定义FieldNamingStrategy

通过实现FieldNamingStrategy接口,可以自定义Java字段名到JSON字段名的映射规则。例如:

public class CustomFieldNamingStrategy implements FieldNamingStrategy {
    @Override
    public String translateName(Field field) {
        // 将Java字段名转换为大写
        return field.getName().toUpperCase();
    }
}

// 使用自定义命名策略
Gson gson = new GsonBuilder()
    .setFieldNamingStrategy(new CustomFieldNamingStrategy())
    .create();

6.2 自定义ExclusionStrategy

通过实现ExclusionStrategy接口,可以自定义字段排除规则。例如:

public class CustomExclusionStrategy implements ExclusionStrategy {
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        // 排除所有以"secret"开头的字段
        return f.getName().startsWith("secret");
    }
    
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        // 不排除任何类
        return false;
    }
}

// 使用自定义排除策略
Gson gson = new GsonBuilder()
    .addSerializationExclusionStrategy(new CustomExclusionStrategy())
    .addDeserializationExclusionStrategy(new CustomExclusionStrategy())
    .create();

6.3 与其他TypeAdapterFactory结合

ReflectiveTypeAdapterFactory可以与其他TypeAdapterFactory结合使用,以处理特殊类型或场景。例如:

// 创建自定义工厂
class CustomTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (type.getRawType() == MySpecialType.class) {
            return (TypeAdapter<T>) new MySpecialTypeAdapter();
        }
        return null;
    }
}

// 注册自定义工厂
Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new CustomTypeAdapterFactory())
    .create();

在这个例子中,CustomTypeAdapterFactory会优先处理MySpecialType类型,而其他类型仍由ReflectiveTypeAdapterFactory处理。

七、总结与展望

7.1 ReflectiveTypeAdapterFactory的优势

ReflectiveTypeAdapterFactory作为Gson的核心组件,具有以下优势:

  1. 自动化:无需为每个Java类编写显式的序列化和反序列化代码,大大简化了开发流程。
  2. 灵活性:通过注解和策略接口,可以灵活配置序列化和反序列化行为。
  3. 广泛适用性:能够处理大多数普通Java对象,包括嵌套结构和集合。
  4. 可扩展性:可以通过自定义FieldNamingStrategy、ExclusionStrategy等进行扩展。

7.2 未来发展方向

随着Java和Android技术的发展,ReflectiveTypeAdapterFactory可能会在以下方向发展:

  1. 编译时处理:引入编译时注解处理,在编译期生成反射代码,进一步提高性能。
  2. Kotlin支持:更好地支持Kotlin语言特性,如数据类、协程等。
  3. 多平台支持:在Kotlin Multiplatform项目中提供更好的支持,实现跨平台的数据转换。
  4. 性能优化:继续优化反射性能,减少反射开销。
  5. 简化API:提供更简洁的API,降低开发者使用门槛。

通过不断优化和扩展,ReflectiveTypeAdapterFactory将继续作为Gson的核心组件,为开发者提供高效、灵活的Java对象与JSON数据之间的转换解决方案。