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

使用Gson @JsonAdapter注解实现自定义POJO序列化问题

解决方案:自定义TypeAdapter实现字段平级序列化/反序列化

我来帮你搞定这个Gson序列化的问题!你想要把嵌套的address字段平级到根节点,同时保持反序列化正常,用自定义TypeAdapter配合@JsonAdapter注解就能完美实现,具体步骤如下:

1. 确认你的POJO结构

假设你的实体类是这样的(如果结构不同,只需对应调整适配器代码即可):

// User类,包含嵌套的Address对象
public class User {
    private String name;
    private String email;
    private Address address;

    // 构造方法、getter和setter省略
}

// Address类,包含地址相关字段
public class Address {
    private String address_line1;
    private String address_line2;
    private String address_city;
    private String address_postalcode;

    // 构造方法、getter和setter省略
}

2. 自定义TypeAdapter

这个适配器会负责处理User的序列化和反序列化逻辑,核心是序列化时把Address的字段“拆”到根节点,反序列化时再把平级字段重新组装成Address对象:

import com.google.gson.*;
import java.io.IOException;
import java.util.Map;

public class UserTypeAdapter extends TypeAdapter<User> {
    // 复用Gson实例来处理嵌套对象的序列化/反序列化,减少重复代码
    private final Gson gson = new Gson();

    @Override
    public void write(JsonWriter out, User user) throws IOException {
        out.beginObject();
        
        // 先写入User本身的根节点字段
        out.name("name").value(user.getName());
        out.name("email").value(user.getEmail());
        
        // 把Address的字段直接写入根节点(而非嵌套的address对象)
        Address address = user.getAddress();
        if (address != null) {
            JsonObject addressJson = gson.toJsonTree(address).getAsJsonObject();
            for (Map.Entry<String, JsonElement> entry : addressJson.entrySet()) {
                out.name(entry.getKey());
                gson.toJson(entry.getValue(), out);
            }
        }
        
        out.endObject();
    }

    @Override
    public User read(JsonReader in) throws IOException {
        JsonObject jsonObject = gson.fromJson(in, JsonObject.class);
        
        // 读取根节点的name和email字段
        String name = jsonObject.get("name").getAsString();
        String email = jsonObject.get("email").getAsString();
        
        // 提取平级的地址字段,组装成Address对象
        JsonObject addressJson = new JsonObject();
        // 列出所有Address类的字段名
        String[] addressFieldNames = {"address_line1", "address_line2", "address_city", "address_postalcode"};
        for (String fieldName : addressFieldNames) {
            if (jsonObject.has(fieldName)) {
                addressJson.add(fieldName, jsonObject.get(fieldName));
            }
        }
        Address address = gson.fromJson(addressJson, Address.class);
        
        // 组装User对象并返回
        User user = new User();
        user.setName(name);
        user.setEmail(email);
        user.setAddress(address);
        return user;
    }
}

3. 给User类添加@JsonAdapter注解

把自定义的适配器绑定到User类上,这样Gson处理User的序列化/反序列化时就会自动使用这个适配器:

import com.google.gson.annotations.JsonAdapter;

@JsonAdapter(UserTypeAdapter.class)
public class User {
    // 原有的字段和方法
}

4. 测试验证

写个简单的测试代码验证效果:

public class TestGsonAdapter {
    public static void main(String[] args) {
        // 构建测试对象
        Address address = new Address("123 Some Address", "", "My city", "CV31 9GP");
        User user = new User("ana", "test@test.co.uk", address);
        
        // 序列化
        Gson gson = new Gson();
        String serializedJson = gson.toJson(user);
        System.out.println("序列化结果:");
        System.out.println(serializedJson);
        // 输出就是你期望的平级结构:{"name":"ana","email":"test@test.co.uk","address_line1":"123 Some Address",...}
        
        // 反序列化验证
        User deserializedUser = gson.fromJson(serializedJson, User.class);
        System.out.println("\n反序列化后的Address对象:");
        System.out.println(deserializedUser.getAddress().getAddress_line1()); // 输出123 Some Address
    }
}

额外说明

  • 上面的适配器用了gson.toJsonTree(address)来自动序列化Address对象,避免了手动写每个字段,后续Address新增字段时,适配器代码不需要修改,非常灵活。
  • 代码里已经做了null判断,就算address为null也不会抛出空指针异常。
  • 反序列化时通过筛选指定字段组装Address对象,确保只把地址相关的字段传递给Address类的反序列化逻辑,避免冲突。

内容的提问来源于stack exchange,提问作者Ana Varani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:33:18