Android中Gson非基本类型字段默认值失效问题解决方案咨询
解决Gson解析时非基本类型字段保留默认值的问题
你遇到的情况确实是Gson的默认行为导致的:在ReflectiveTypeAdapterFactory.BoundField的read方法中,只有基本类型会在解析值为null时跳过赋值,引用类型则会直接将字段设为null,哪怕你已经在Model中初始化了默认值。下面提供几种实用的解决方案:
方案1:针对集合类型注册全局TypeAdapterFactory
如果你的需求主要是处理List这类集合的空值问题,可以编写一个全局的TypeAdapterFactory,让所有List类型字段在解析到null时自动返回空列表:
步骤1:编写EmptyListTypeAdapterFactory
public class EmptyListTypeAdapterFactory implements TypeAdapterFactory { @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { // 只处理List类型 if (!List.class.isAssignableFrom(type.getRawType())) { return null; } // 获取Gson默认的TypeAdapter作为委托 TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(this, type); return (TypeAdapter<T>) new EmptyListTypeAdapter<>((TypeAdapter<List<?>>) delegateAdapter); } private static class EmptyListTypeAdapter<E> extends TypeAdapter<List<E>> { private final TypeAdapter<List<E>> delegate; EmptyListTypeAdapter(TypeAdapter<List<E>> delegate) { this.delegate = delegate; } @Override public void write(JsonWriter out, List<E> value) throws IOException { delegate.write(out, value); } @Override public List<E> read(JsonReader in) throws IOException { List<E> list = delegate.read(in); // 如果解析结果为null,返回空ArrayList return list != null ? list : new ArrayList<>(); } } }
步骤2:注册到GsonBuilder
创建Gson实例时注册这个Factory,同时保留你的@Expose注解配置:
Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .registerTypeAdapterFactory(new EmptyListTypeAdapterFactory()) .create();
这样所有List类型的字段,无论是JSON中不存在还是值为null,都会自动返回空列表,无需逐个字段处理。
方案2:自定义通用TypeAdapterFactory处理所有引用类型
如果你希望所有引用类型(不仅是List)都能保留默认值,可以编写一个更通用的Factory,当解析到null时,不覆盖Model中已初始化的字段值:
步骤1:编写DefaultValuePreserveAdapterFactory
这个Factory会修改Gson的默认赋值逻辑,让引用类型和基本类型一样,在解析值为null时跳过赋值:
public class DefaultValuePreserveAdapterFactory implements TypeAdapterFactory { @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { // 只处理自定义Model类,跳过系统类 if (type.getRawType().isPrimitive() || type.getRawType().isAssignableFrom(String.class)) { return null; } final TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(this, type); return new TypeAdapter<T>() { @Override public void write(JsonWriter out, T value) throws IOException { delegateAdapter.write(out, value); } @Override public T read(JsonReader in) throws IOException { // 先创建实例,保留初始化的默认值 T instance = null; try { instance = type.getRawType().newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException("Model类需要无参构造函数", e); } // 解析JSON元素 JsonElement element = JsonParser.parseReader(in); if (element.isJsonObject()) { JsonObject jsonObject = element.getAsJsonObject(); // 遍历所有带@Expose的字段 for (Field field : type.getRawType().getDeclaredFields()) { if (field.isAnnotationPresent(Expose.class)) { field.setAccessible(true); String fieldName = field.getName(); if (jsonObject.has(fieldName)) { JsonElement fieldElement = jsonObject.get(fieldName); // 仅当字段值非null时,覆盖原有值 if (!fieldElement.isJsonNull()) { Object fieldValue = gson.fromJson(fieldElement, field.getType()); field.set(instance, fieldValue); } } } } } return instance; } }; } }
步骤2:注册使用
同样注册到GsonBuilder即可,这个方案会让所有带@Expose注解的引用类型字段,在解析到null时保留初始化的默认值。
方案3:单个字段指定JsonAdapter
如果只有少数字段需要处理,可以直接在字段上使用@JsonAdapter注解,指定自定义TypeAdapter:
步骤1:编写单个字段的TypeAdapter
public class EmptyStringListAdapter extends TypeAdapter<List<String>> { private final TypeAdapter<List<String>> delegate = new Gson().getAdapter(TypeToken.get(List.class)); @Override public void write(JsonWriter out, List<String> value) throws IOException { delegate.write(out, value); } @Override public List<String> read(JsonReader in) throws IOException { List<String> list = delegate.read(in); return list != null ? list : new ArrayList<>(); } }
步骤2:在Model中使用
class Model { @Expose private int test = 1; @Expose private int primitive = 1; @Expose @JsonAdapter(EmptyStringListAdapter.class) private List<String> strings = new ArrayList<>(); }
注意事项
- 确保你的Model类有无参构造函数,Gson默认依赖无参构造创建实例,否则初始化的默认值不会生效。
- 如果Model是内部类,需要声明为
static,否则Gson无法正确创建实例。
内容的提问来源于stack exchange,提问作者Vladyslav Komarov
相关产品推荐
相关产品推荐

