Gson序列化缺失嵌套字段处理:避免NullPointerException问题求助
解决Gson序列化时嵌套字段缺失导致的NullPointerException问题
我使用Gson进行数据的反序列化/序列化操作,先将JSON直接转换为POJO,再通过自定义序列化处理输出。但当JSON中存在缺失的嵌套字段时,序列化步骤访问这些字段会抛出NullPointerException:比如传入的JSON没有address字段时,访问address.city会触发异常;缺少整个description字段时,访问description.info也会报错。希望能在字段缺失时自动填充默认值,同时避免手动强制判空。
解决方案
方法1:初始化POJO中的嵌套对象(推荐)
在POJO的无参构造方法中初始化所有嵌套类实例,这样即使JSON没有对应字段,嵌套对象也不会为null,访问子字段时只会得到null而非抛出异常。
修改后的MyCustomer类代码:
import com.google.gson.*; import org.junit.Test; import java.lang.reflect.Type; import java.util.Date; public class MyGsonTest { class MyCustomer { String id; String name; Date birthdate; Address address; Description description; // 无参构造,初始化所有嵌套对象 public MyCustomer() { this.address = new Address(); this.description = new Description(); } class Address { String city; String zipCode; Street street; public Address() { this.street = new Street(); } class Street { String apartment; String number; } } class Description { String info; String moreInfo; } } // 自定义序列化类无需额外判空,直接访问字段即可 public class MyCustomerSerializer implements JsonSerializer<MyCustomer> { @Override public JsonElement serialize(MyCustomer myCustomer, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject jo = new JsonObject(); jo.addProperty("city", myCustomer.address.city); jo.addProperty("zipcode", myCustomer.address.zipCode); jo.addProperty("info", myCustomer.description.info); jo.addProperty("moreInfo", myCustomer.description.moreInfo); // 若需要填充默认值而非输出null,可直接替换 jo.addProperty("info", myCustomer.description.info == null ? "默认信息" : myCustomer.description.info); return jo; } } @Test public void testRun() { Gson gson = new GsonBuilder() .registerTypeAdapter(MyCustomer.class, new MyCustomerSerializer()) .create(); String myCustomer1String = "{'id':'a123','name':'John','birthdate':'1987-01-01','address':{'city':'Colorado'}}"; MyCustomer myCustomer = gson.fromJson(myCustomer1String, MyCustomer.class); String myCustomerParsed = gson.toJson(myCustomer); } }
方法2:用工具类实现安全字段访问(无需修改POJO)
如果无法修改POJO源码,可以编写一个工具方法,通过Lambda表达式安全获取嵌套字段的值,捕获可能的NullPointerException:
public class MyCustomerSerializer implements JsonSerializer<MyCustomer> { @Override public JsonElement serialize(MyCustomer myCustomer, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject jo = new JsonObject(); // 安全访问嵌套字段,缺失时返回null jo.addProperty("city", safeGet(() -> myCustomer.address.city)); jo.addProperty("zipcode", safeGet(() -> myCustomer.address.zipCode)); jo.addProperty("info", safeGet(() -> myCustomer.description.info)); jo.addProperty("moreInfo", safeGet(() -> myCustomer.description.moreInfo)); // 填充默认值示例 jo.addProperty("info", safeGet(() -> myCustomer.description.info) == null ? "默认信息" : safeGet(() -> myCustomer.description.info)); return jo; } // 通用安全获取方法 private <T> T safeGet(Supplier<T> supplier) { try { return supplier.get(); } catch (NullPointerException e) { return null; } } }
方法3:结合Optional与Gson空值策略
利用Java的Optional类处理嵌套null,同时配置Gson的空值序列化策略:
public class MyCustomerSerializer implements JsonSerializer<MyCustomer> { @Override public JsonElement serialize(MyCustomer myCustomer, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject jo = new JsonObject(); // 用Optional链式调用安全获取字段 String city = Optional.ofNullable(myCustomer.address).map(a -> a.city).orElse(null); String info = Optional.ofNullable(myCustomer.description).map(d -> d.info).orElse("默认信息"); jo.addProperty("city", city); jo.addProperty("info", info); return jo; } } // 初始化Gson时配置空值策略 Gson gson = new GsonBuilder() .registerTypeAdapter(MyCustomer.class, new MyCustomerSerializer()) .serializeNulls() // 允许序列化null值(可选,根据需求决定) .create();
总结
- 若有权限修改POJO,优先使用方法1,从根源避免NullPointerException,代码最简洁易维护。
- 无法修改POJO时,选择方法2的工具类或方法3的Optional方案,灵活处理嵌套字段缺失场景。
内容的提问来源于stack exchange,提问作者Tomasz Kubat
相关产品推荐
相关产品推荐

