Gson序列化Map对象键后反序列化报错,求正确实现方案
解决Gson反序列化自定义对象为键的Map报错问题
问题根源:Gson默认会将非基本类型的Map键转为字符串(调用对象的toString()方法),反序列化时无法将该字符串还原为自定义对象,导致JsonSyntaxException。必须为作为Map键的Chunk和Location类自定义TypeAdapter,指定序列化/反序列化规则。
步骤1:为Chunk类编写TypeAdapter
利用Chunk的final字段生成唯一标识字符串,反序列化时解析字符串重建对象:
public class ChunkTypeAdapter extends TypeAdapter<Chunk> { @Override public void write(JsonWriter out, Chunk chunk) throws IOException { // 用无冲突分隔符拼接字段,生成键字符串 String key = chunk.getWorldName() + "|" + chunk.getX() + "|" + chunk.getZ(); out.value(key); } @Override public Chunk read(JsonReader in) throws IOException { String key = in.nextString(); String[] parts = key.split("\\|"); String worldName = parts[0]; int x = Integer.parseInt(parts[1]); int z = Integer.parseInt(parts[2]); return new Chunk(worldName, x, z); } }
步骤2:为Location类编写TypeAdapter
逻辑与Chunk一致,多处理一个y字段:
public class LocationTypeAdapter extends TypeAdapter<Location> { @Override public void write(JsonWriter out, Location location) throws IOException { String key = location.getWorldName() + "|" + location.getX() + "|" + location.getY() + "|" + location.getZ(); out.value(key); } @Override public Location read(JsonReader in) throws IOException { String key = in.nextString(); String[] parts = key.split("\\|"); String worldName = parts[0]; int x = Integer.parseInt(parts[1]); int y = Integer.parseInt(parts[2]); int z = Integer.parseInt(parts[3]); return new Location(worldName, x, y, z); } }
步骤3:注册TypeAdapter并创建Gson实例
将自定义TypeAdapter注册到GsonBuilder,覆盖默认的键处理逻辑:
Gson gson = new GsonBuilder() .registerTypeAdapter(Chunk.class, new ChunkTypeAdapter()) .registerTypeAdapter(Location.class, new LocationTypeAdapter()) .create();
步骤4:修改序列化/反序列化方法
使用自定义Gson实例处理Map:
// 保存方法 public void saveChests(Map<Chunk, LinkedHashMap<Location, ChestObject>> chestMap, String filePath) throws IOException { try (FileWriter writer = new FileWriter(filePath)) { gson.toJson(chestMap, writer); } } // 恢复方法 public Map<Chunk, LinkedHashMap<Location, ChestObject>> recoverChests(String filePath) throws IOException { try (FileReader reader = new FileReader(filePath)) { Type type = new TypeToken<Map<Chunk, LinkedHashMap<Location, ChestObject>>>() {}.getType(); return gson.fromJson(reader, type); } }
可选优化:用JSON字符串作为键
如果担心字段包含分隔符,可将对象序列化为JSON字符串作为键,更通用:
// ChunkTypeAdapter的替代实现 public class ChunkTypeAdapter extends TypeAdapter<Chunk> { private final Gson internalGson = new Gson(); @Override public void write(JsonWriter out, Chunk chunk) throws IOException { String json = internalGson.toJson(chunk); out.value(json); } @Override public Chunk read(JsonReader in) throws IOException { String json = in.nextString(); return internalGson.fromJson(json, Chunk.class); } }
内容的提问来源于stack exchange,提问作者HowDoISolveThis
相关产品推荐
相关产品推荐

