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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:25:36