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

如何使用Gson将结构相似的JSON转换为不同的POJO?

问题场景与现有实现问题

我有两个分别用于登录和订单场景的JSON:

{
  "head": {
    "requestCode": "code"
  },
  "body": {
    "reqId": "xyz",
    "userName": "xyz",
    "passwd": "xyz"
  }
}

{
  "head": {
    "requestCode": "code"
  },
  "body": {
    "reqId": "xyz",
    "orderId": "xyz"
  }
}

我希望编写Java POJO时复用head以及body中的reqId公共部分,仅区分body的其余内容,于是设计了如下POJO结构:

public class Base<T extends Body> {

    @SerializedName("head")
    @Expose
    public Head head;
    @SerializedName("body")
    @Expose
    private T body;
}

public class Body {
    @SerializedName("clientCode")
    @Expose
    private String clientCode;
}

public class Head {
    @SerializedName("requestCode")
    @Expose
    public String requestCode;
}

public class Login extends Body {
    @SerializedName("userName")
    @Expose
    public String userName;
    @SerializedName("passwd")
    @Expose
    public String passed;
}

public class Order extends Body {
    @SerializedName("orderId")
    @Expose
    String orderId;
}

但实际使用中发现Gson无法基于嵌套参数化类型解析并构建对象,请问有没有更优的实现方式?(注:JSON结构不会改变)


优化实现方案

方案一:修正POJO结构 + 显式指定泛型类型

1. 修正POJO定义

首先修正两个明显的匹配错误,并把body的公共字段reqId移到父类Body中,确保公共部分被正确复用:

// 公共Head类,保持不变
public class Head {
    @SerializedName("requestCode")
    @Expose
    public String requestCode;
}

// 修正Body类,添加公共的reqId字段,移除无关的clientCode
public class Body {
    @SerializedName("reqId")
    @Expose
    private String reqId;

    // 添加入参getter/setter,方便外部访问
    public String getReqId() {
        return reqId;
    }

    public void setReqId(String reqId) {
        this.reqId = reqId;
    }
}

// 修正Login类的字段名,与JSON的passwd对应
public class Login extends Body {
    @SerializedName("userName")
    @Expose
    public String userName;
    @SerializedName("passwd")
    @Expose
    public String passwd;
}

// Order类保持逻辑,补充访问修饰符
public class Order extends Body {
    @SerializedName("orderId")
    @Expose
    private String orderId;

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}

// 泛型Base类,补充body的getter/setter
public class Base<T extends Body> {
    @SerializedName("head")
    @Expose
    public Head head;
    @SerializedName("body")
    @Expose
    private T body;

    public T getBody() {
        return body;
    }

    public void setBody(T body) {
        this.body = body;
    }
}

2. 使用TypeToken解析泛型对象

由于Java的类型擦除机制,Gson无法直接识别Base<Login>这类嵌套泛型的具体类型,需要通过TypeToken显式声明:

// 初始化Gson实例,启用@Expose注解过滤
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

// 解析登录JSON
Type loginBaseType = new TypeToken<Base<Login>>() {}.getType();
Base<Login> loginBase = gson.fromJson(loginJsonStr, loginBaseType);

// 解析订单JSON
Type orderBaseType = new TypeToken<Base<Order>>() {}.getType();
Base<Order> orderBase = gson.fromJson(orderJsonStr, orderBaseType);

方案二:自定义TypeAdapter(适用于复杂解析场景)

如果需要更灵活的解析逻辑,可以自定义TypeAdapter直接控制Base类的序列化/反序列化流程:

public class BaseTypeAdapter<T extends Body> extends TypeAdapter<Base<T>> {
    private final Class<T> bodyClass;
    private final Gson gson;

    public BaseTypeAdapter(Class<T> bodyClass) {
        this.bodyClass = bodyClass;
        this.gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
    }

    @Override
    public void write(JsonWriter out, Base<T> value) throws IOException {
        // 序列化逻辑,直接复用Gson默认实现
        gson.toJson(value, Base.class, out);
    }

    @Override
    public Base<T> read(JsonReader in) throws IOException {
        JsonObject jsonObject = gson.fromJson(in, JsonObject.class);
        Base<T> base = new Base<>();
        // 单独解析head部分
        base.head = gson.fromJson(jsonObject.get("head"), Head.class);
        // 解析body为指定的子类类型
        base.setBody(gson.fromJson(jsonObject.get("body"), bodyClass));
        return base;
    }
}

使用时直接指定对应的Body子类即可:

// 解析登录JSON
BaseTypeAdapter<Login> loginAdapter = new BaseTypeAdapter<>(Login.class);
Base<Login> loginBase = loginAdapter.fromJson(loginJsonStr);

// 解析订单JSON
BaseTypeAdapter<Order> orderAdapter = new BaseTypeAdapter<>(Order.class);
Base<Order> orderBase = orderAdapter.fromJson(orderJsonStr);

内容的提问来源于stack exchange,提问作者Pankaj Patel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:27:33