You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GSON反序列化时如何获取ObservableField未初始化的所属对象?

解决方案:通过反射拦截实体类反序列化,传递Owner实例

你的核心问题在于:Gson反序列化时,ObservableField的所属对象(比如Member)会先被创建(通过Unsafe初始化空实例),但ObservableField的构造器必须传入该Owner实例,而单独的ObservableField TypeAdapter无法获取到这个已创建的Owner。

解决思路是不为ObservableField单独编写TypeAdapter,而是为所有包含ObservableField的实体类编写通用TypeAdapterFactory,在实体类反序列化过程中,拿到已创建的实体实例,再为ObservableField字段传入该实例作为Owner。

实现代码

通用TypeAdapterFactory

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;

public class ObservableFieldOwnerTypeAdapterFactory implements TypeAdapterFactory {

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        Class<T> clazz = (Class<T>) typeToken.getRawType();

        // 检查当前类是否包含ObservableField类型的字段
        boolean hasObservableField = Arrays.stream(clazz.getDeclaredFields())
                .anyMatch(field -> ObservableField.class.isAssignableFrom(field.getType()));
        if (!hasObservableField) {
            return null; // 无ObservableField字段,交给Gson默认适配器处理
        }

        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                // 序列化时直接委托给Gson默认逻辑
                gson.getAdapter(typeToken).write(out, value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                // 1. 创建未初始化的实体对象(和Gson默认行为一致)
                T instance = gson.newInstance(typeToken.getType());
                // 2. 将JSON解析为JsonObject,方便逐个处理字段
                JsonElement jsonElement = gson.fromJson(in, JsonElement.class);
                JsonObject jsonObject = jsonElement.getAsJsonObject();

                // 3. 遍历实体类所有字段
                for (Field field : clazz.getDeclaredFields()) {
                    field.setAccessible(true);
                    String jsonFieldName = gson.fieldNamingStrategy().translateName(field);
                    JsonElement fieldJson = jsonObject.get(jsonFieldName);
                    if (fieldJson == null) continue;

                    if (ObservableField.class.isAssignableFrom(field.getType())) {
                        // 处理ObservableField类型字段
                        if (field.getGenericType() instanceof ParameterizedType paramType) {
                            // 获取ObservableField的Value类型参数
                            Type valueType = paramType.getActualTypeArguments()[1];
                            Object fieldValue = gson.fromJson(fieldJson, valueType);

                            // 创建ObservableField实例,传入当前实体作为Owner
                            ObservableField<?, ?> observableField = new ObservableField<>(instance, fieldValue);
                            field.set(instance, observableField);
                        }
                    } else {
                        // 处理普通字段,委托给Gson默认反序列化
                        Object fieldValue = gson.fromJson(fieldJson, field.getGenericType());
                        field.set(instance, fieldValue);
                    }
                }
                return instance;
            }
        };
    }
}

注册Factory到Gson

Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(new ObservableFieldOwnerTypeAdapterFactory())
        .create();

// 测试反序列化
String json = "{\"id\":\"550e8400-e29b-41d4-a716-446655440000\",\"balance\":100}";
Member member = gson.fromJson(json, Member.class);
System.out.println(member.getBalance().getOwner() == member); // 输出true,验证Owner正确关联

关键原理说明

  1. 拦截实体类反序列化:Factory会自动识别包含ObservableField的类,为其创建自定义TypeAdapter
  2. 先创建实体实例:利用Gson的newInstance方法创建未初始化的实体对象(和Gson默认用Unsafe创建的逻辑一致)
  3. 逐个处理字段:解析JSON为JsonObject后,遍历实体字段,遇到ObservableField时,直接传入已创建的实体实例作为Owner,再赋值给字段
  4. 兼容普通字段:非ObservableField字段仍委托给Gson默认反序列化逻辑,保证原有功能不受影响

注意事项

  • 确保实体类的字段可以被反射访问(代码中已设置field.setAccessible(true))
  • 如果实体类使用了@SerializedName注解,gson.fieldNamingStrategy().translateName(field)会自动处理JSON字段名映射
  • 若实体类有继承关系,需要额外遍历父类字段(可在代码中添加Class<?> currentClazz = clazz; while(currentClazz != null) { ... currentClazz = currentClazz.getSuperclass(); }逻辑)

内容的提问来源于stack exchange,提问作者Toshimichi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:20:13