使用GSON从嵌套类取值并在构造方法中赋值的问题
解决GSON反序列化时构造方法依赖字段为null的问题
嘿,我刚踩过类似的坑,来给你捋清楚怎么搞定这个问题~
首先得明确GSON默认的反序列化逻辑:它会先创建类的实例(要么调用无参构造,要么用Unsafe绕开构造直接生成对象),然后才会把JSON里的字段值通过反射赋值给类的成员变量。所以你在Class1的构造方法里去拿className肯定是null——因为这时候GSON还没给这个字段赋值呢!
那要实现「从子类(不管是JSON里的子结构还是Java子类)取值并在构造方法中赋值」,有几个靠谱的方案:
方案1:自定义JsonDeserializer手动控制实例创建
这是最直接的解决办法,你可以自己接管反序列化的全过程,先从JSON里把需要的className(包括子类嵌套结构里的)取出来,再调用带参数的构造方法创建实例,最后把其他字段也补上。
举个代码例子:
public class Class1Deserializer implements JsonDeserializer<Class1> { @Override public Class1 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // 先把JSON元素转成JsonObject JsonObject jsonObj = json.getAsJsonObject(); // 假设className在子类的嵌套结构里,比如JSON里有个"subClass"对象包含它 String className = jsonObj.getAsJsonObject("subClass") .get("className") .getAsString(); // 用拿到的className调用带参构造,不会再出现null的情况 Class1 class1Instance = new Class1(className); // 让GSON帮你处理剩下的字段赋值 context.deserialize(json, Class1.class); return class1Instance; } }
然后把这个反序列化器注册到GSON中:
Gson gson = new GsonBuilder() .registerTypeAdapter(Class1.class, new Class1Deserializer()) .create(); // 反序列化JSON数组 List<Class1> class1List = gson.fromJson(jsonArrayStr, new TypeToken<List<Class1>>(){}.getType());
方案2:重构代码,把构造逻辑移到初始化方法
如果不想写自定义反序列化器,最简单的方式就是把构造方法里依赖className的逻辑抽出来,放到一个单独的初始化方法里,等GSON完成反序列化后再手动调用。
比如:
public class Class1 { private String className; // 保留无参构造,让GSON能正常创建实例 public Class1() {} // 初始化方法,反序列化完成后调用 public void init() { if (className == null) { throw new IllegalArgumentException("className 不能为null"); } // 原来构造方法里的逻辑全移到这里 } }
然后反序列化后遍历执行初始化:
List<Class1> class1List = gson.fromJson(jsonArrayStr, new TypeToken<List<Class1>>(){}.getType()); for (Class1 item : class1List) { item.init(); }
额外提醒:检查字段映射是否正确
有时候className为null可能只是因为JSON里的字段名和Java类里的字段名不匹配,比如JSON里是class_name但Java里是className,这时候可以用@SerializedName注解来做映射:
public class Class1 { @SerializedName("class_name") // 对应JSON里的字段名 private String className; // ... }
内容的提问来源于stack exchange,提问作者LorenzoBerti
相关产品推荐
相关产品推荐

