GSON使用TypeAdapter自定义反序列化Dto的优化方案咨询
GSON自定义反序列化优化方案
问题说明
现有代码可正常运行,目标是将如下JSON字符串:
{"d": [{"d1": "D1"}, {"d2": "D2"}]}
通过GSON及自定义TypeAdapter<Dto>反序列化为Dto类型对象。当前手写的DtoAdapter需要手动维护JSON节点的开始/结束标记,逻辑繁琐,以下提供更简洁的实现方式,以及其他GSON自定义反序列化方案。
原有实现代码
public class Main { public static void main(String[] args) { GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Dto.class, new DtoAdapter()); Gson gson = builder.create(); String json = "{\"d\": [{\"d1\": \"D1\"}, {\"d2\": \"D2\"}]}"; Dto dto = gson.fromJson(json, Dto.class); System.out.println(dto); // Dto(items=[Dto.Item(name=D1 custom case 1), Dto.Item(name=D2 custom case 2)]) } } class DtoAdapter extends TypeAdapter<Dto> { @Override public Dto read(JsonReader reader) throws IOException { Dto dto = new Dto(); reader.beginObject(); // Start JSON string {...} while (reader.hasNext()) { switch (reader.nextName()) { case "d": reader.beginArray(); // Start Array {"d": [...]} while (reader.hasNext()) { reader.beginObject(); // Start Object in Array {"d": [{...}, ]} Dto.Item item = new Dto.Item(); switch (reader.nextName()) { case "d1": item.setName(reader.nextString() + " custom case 1"); dto.getItems().add(item); break; case "d2": item.setName(reader.nextString() + " custom case 2"); dto.getItems().add(item); break; } reader.endObject(); // End Object in Array } reader.endArray(); // End Array break; } } reader.endObject(); // End JSON string return dto; } @Override public void write(JsonWriter writer, Dto dto) throws IOException { // Serialize } } @Data public class Dto { List<Item> items = new ArrayList<>(); @Data public static class Item { private String name; } }
优化方案
方案1:简化流式TypeAdapter实现
原有TypeAdapter繁琐的核心原因是手动调用beginObject/endObject/beginArray/endArray维护嵌套层级,实际上可以在TypeAdapter内部委托默认GSON实例将当前流节点直接转为JsonElement树结构,跳过手动维护边界的步骤,同时保留流式解析的高性能优势:
class DtoAdapter extends TypeAdapter<Dto> { private static final Gson defaultGson = new Gson(); @Override public Dto read(JsonReader reader) throws IOException { JsonObject root = defaultGson.fromJson(reader, JsonObject.class); Dto dto = new Dto(); JsonArray dArray = root.getAsJsonArray("d"); for (JsonElement element : dArray) { JsonObject itemObj = element.getAsJsonObject(); Dto.Item item = new Dto.Item(); for (Map.Entry<String, JsonElement> entry : itemObj.entrySet()) { String key = entry.getKey(); String val = entry.getValue().getAsString(); if ("d1".equals(key)) { item.setName(val + " custom case 1"); } else if ("d2".equals(key)) { item.setName(val + " custom case 2"); } dto.getItems().add(item); } } return dto; } @Override public void write(JsonWriter writer, Dto dto) throws IOException { // 序列化逻辑按需实现 } }
方案2:使用JsonDeserializer树模型接口
GSON提供了基于树模型的JsonDeserializer接口,不需要操作底层JsonReader流,所有JSON节点会被提前解析为内存中的JsonElement结构,直接按键取值即可,代码更简洁:
class DtoDeserializer implements JsonDeserializer<Dto> { @Override public Dto deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Dto dto = new Dto(); JsonArray dArray = json.getAsJsonObject().getAsJsonArray("d"); for (JsonElement element : dArray) { JsonObject itemObj = element.getAsJsonObject(); Dto.Item item = new Dto.Item(); if (itemObj.has("d1")) { item.setName(itemObj.get("d1").getAsString() + " custom case 1"); } else if (itemObj.has("d2")) { item.setName(itemObj.get("d2").getAsString() + " custom case 2"); } dto.getItems().add(item); } return dto; } }
注册方式和TypeAdapter一致:
Gson gson = new GsonBuilder() .registerTypeAdapter(Dto.class, new DtoDeserializer()) .create();
方案3:注解映射+细粒度反序列化器
通过@SerializedName注解完成JSON字段到Java字段的自动映射,只需要为存在特殊转换逻辑的Item类编写反序列化器,逻辑解耦性更好,后续维护成本更低:
- 修改Dto类添加字段映射注解
@Data public class Dto { @SerializedName("d") // 自动映射JSON中的d数组到items字段 List<Item> items = new ArrayList<>(); @Data public static class Item { private String name; } } - 只编写Item类的反序列化逻辑
class ItemDeserializer implements JsonDeserializer<Dto.Item> { @Override public Dto.Item deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); Dto.Item item = new Dto.Item(); if (obj.has("d1")) { item.setName(obj.get("d1").getAsString() + " custom case 1"); } else if (obj.has("d2")) { item.setName(obj.get("d2").getAsString() + " custom case 2"); } return item; } } - 注册反序列化器
Gson gson = new GsonBuilder() .registerTypeAdapter(Dto.Item.class, new ItemDeserializer()) .create();
方案选型参考
- 简化版流式
TypeAdapter:性能最优,适合大体积JSON解析场景 JsonDeserializer实现:开发效率最高,代码最简洁,适合绝大多数常规业务场景- 注解+细粒度反序列化器:可维护性最好,适合类属性多、仅少数字段需要特殊转换的场景
内容的提问来源于stack exchange,提问作者Anne Maier
相关产品推荐
相关产品推荐

