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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:35:17