使用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
相关产品推荐
相关产品推荐

