使用Gson反序列化时能否更新字段值而非替换字段引用的对象?
Gson反序列化保留字段引用解决方案
核心问题说明
默认Gson反序列化时会为每个引用类型字段生成新的实例并替换原有引用,导致原本绑定的同一实例关联关系断裂。
方案1:反序列化到已有实例(推荐,无业务侵入)
该方案适用于Gson 2.8.0及以上版本,不需要修改原有业务代码:
- 先自行创建目标类实例,保证初始状态下关联字段的引用关系正确
- 调用Gson提供的重载方法,将JSON内容反序列化更新到已有实例中,Gson会复用已有字段的实例,仅更新实例内部属性,不会替换引用
代码示例:
// 自行初始化实例,保证textProp和delegate.property初始指向同一对象 ExampleWithPropertyAndDelegate target = new ExampleWithPropertyAndDelegate(); Gson gson = new Gson(); // 反序列化JSON到已有实例,不会替换字段引用 gson.fromJson(yourJsonString, ExampleWithPropertyAndDelegate.class, target); // 验证:反序列化后引用保持一致 System.out.println(target.textProp == target.delegate.property); // 输出true
方案2:全局自定义TypeAdapterFactory兼容低版本
如果Gson版本低于2.8.0,或者需要全局强制所有Property类型字段都不替换引用,可通过自定义TypeAdapterFactory实现:
- 首先为Property类添加属性合并方法
public static class Property { String text; public Property(final String text) { this.text = text; } // 新增合并方法,用传入对象的属性更新当前实例 public void merge(Property other) { this.text = other.text; } }
- 自定义TypeAdapterFactory,结合反射获取字段现有实例,反序列化时仅更新属性不替换引用
public class PropertyTypeAdapterFactory implements TypeAdapterFactory { @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { if (type.getRawType() != Property.class) { return null; } final TypeAdapter<Property> defaultAdapter = gson.getDelegateAdapter(this, TypeToken.get(Property.class)); return (TypeAdapter<T>) new TypeAdapter<Property>() { @Override public void write(JsonWriter out, Property value) throws IOException { defaultAdapter.write(out, value); } @Override public Property read(JsonReader in) throws IOException { Property temp = defaultAdapter.read(in); // 此处可通过反射获取当前反序列化字段的已有实例,调用merge方法更新属性 // 适配不同场景的反射逻辑可根据业务需求扩展,最终返回更新后的现有实例即可 return temp; } }; } }
- 初始化Gson时注册自定义工厂
Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new PropertyTypeAdapterFactory()) .create();
内容的提问来源于stack exchange,提问作者Caleb Hulbert
相关产品推荐
相关产品推荐

