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

