如何用GSON反序列化无成员名的极简API响应为POJO?
如何正确将极简订单簿JSON响应转换为类型安全的POJO(GSON)
咱们先梳理下问题:你调用的这个/api/v1/depth接口返回的订单簿响应里,bids和asks都是固定位置的嵌套列表,但用jsonschema2pojo生成的OrderBook类里只是简单用了List<List<String>>,完全没有体现出每个子列表的结构语义,而且GSON确实没有按位置映射的注解,所以得手动处理这个问题。
下面给你两种实用的解决方案:
方法一:自定义TypeAdapter(推荐用于高频反序列化场景)
这种方式最灵活,性能也最好,直接告诉GSON怎么把嵌套列表转换成我们定义的实体类。
步骤1:定义订单条目实体类
先创建一个OrderEntry类,用来对应每个bids/asks的子列表:
public class OrderEntry { private final String price; private final String quantity; private final List<Void> extra; // 对应第三个空数组,用Void表示无意义的空元素 // 构造方法+Getter(因为是固定结构,用不可变类更安全) public OrderEntry(String price, String quantity, List<Void> extra) { this.price = price; this.quantity = quantity; this.extra = extra; } public String getPrice() { return price; } public String getQuantity() { return quantity; } public List<Void> getExtra() { return extra; } }
步骤2:修改OrderBook类
把原来的嵌套列表换成List<OrderEntry>:
public class OrderBook { @SerializedName("lastUpdateId") public Long lastUpdateId; @SerializedName("bids") public List<OrderEntry> bids = null; @SerializedName("asks") public List<OrderEntry> asks = null; }
步骤3:编写自定义TypeAdapter
这个适配器负责把JSON里的数组转换成OrderEntry对象:
import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class OrderEntryTypeAdapter extends TypeAdapter<OrderEntry> { @Override public void write(JsonWriter out, OrderEntry value) throws IOException { // 如果需要序列化订单条目,这里实现写入逻辑;如果只反序列化,可以留空或者抛出异常 out.beginArray(); out.value(value.getPrice()); out.value(value.getQuantity()); out.beginArray(); out.endArray(); // 第三个元素是空数组 out.endArray(); } @Override public OrderEntry read(JsonReader in) throws IOException { in.beginArray(); // 开始读取子列表 String price = in.nextString(); // 第一个元素:价格 String quantity = in.nextString(); // 第二个元素:数量 // 处理第三个空数组 in.beginArray(); List<Void> emptyList = new ArrayList<>(); while (in.hasNext()) { in.skipValue(); // 因为是空数组,直接跳过所有元素 } in.endArray(); in.endArray(); // 结束子列表读取 return new OrderEntry(price, quantity, emptyList); } }
步骤4:注册TypeAdapter到Gson实例
在创建Gson对象时注册这个适配器,之后就能正常反序列化了:
Gson gson = new GsonBuilder() .registerTypeAdapter(OrderEntry.class, new OrderEntryTypeAdapter()) .create(); // 示例:反序列化JSON响应 String jsonResponse = "{ \"lastUpdateId\": 1027024, \"bids\": [ [ \"4.00000000\", \"431.00000000\", [] ] ], \"asks\": [ [ \"4.00000200\", \"12.00000000\", [] ] ] }"; OrderBook orderBook = gson.fromJson(jsonResponse, OrderBook.class);
方法二:封装原始列表,提供类型安全的Getter(快速实现)
如果你的场景对性能要求不高,或者不想写TypeAdapter,可以用这种更简洁的方式:保留自动生成的嵌套列表,然后通过Getter方法把它转换成类型安全的OrderEntry列表。
修改后的OrderBook类
import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class OrderBook { @SerializedName("lastUpdateId") public Long lastUpdateId; @SerializedName("bids") private List<List<String>> rawBids = null; // 隐藏原始列表 @SerializedName("asks") private List<List<String>> rawAsks = null; // 提供类型安全的Getter,自动转换原始列表 public List<OrderEntry> getBids() { if (rawBids == null) return Collections.emptyList(); return rawBids.stream() .map(rawEntry -> new OrderEntry( rawEntry.get(0), rawEntry.get(1), Collections.emptyList() )) .collect(Collectors.toList()); } public List<OrderEntry> getAsks() { if (rawAsks == null) return Collections.emptyList(); return rawAsks.stream() .map(rawEntry -> new OrderEntry( rawEntry.get(0), rawEntry.get(1), Collections.emptyList() )) .collect(Collectors.toList()); } // 内部静态类:订单条目 public static class OrderEntry { private final String price; private final String quantity; private final List<Void> extra; public OrderEntry(String price, String quantity, List<Void> extra) { this.price = price; this.quantity = quantity; this.extra = extra; } // Getter方法 public String getPrice() { return price; } public String getQuantity() { return quantity; } public List<Void> getExtra() { return extra; } } }
这种方式不需要额外的适配器代码,直接用Java Stream完成转换,适合快速开发。如果担心重复转换的性能问题,可以把转换后的列表缓存起来(比如用lazy加载的方式)。
内容的提问来源于stack exchange,提问作者Someone Somewhere
相关产品推荐
相关产品推荐

