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

使用Gson恢复保存的Map对象时触发JsonSyntaxException异常

问题分析:Gson读取嵌套Map时抛出JsonSyntaxException异常

我有一个嵌套Map结构:Map<Chunk, LinkedHashMap<Location, ChestObject>> CHEST_MAP,其中Chunk、Location、ChestObject类均实现了hashCode、equals和toString方法,成员变量均为final类型。使用Gson将该Map保存到文件的操作完全正常,但读取恢复时抛出如下异常:

[17:17:53 WARN]: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 2 column 4 
[17:17:53 WARN]:        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176) 
[17:17:53 WARN]:        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) 
[17:17:53 WARN]:        at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186) 
[17:17:53 WARN]:        at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) 
[17:17:53 WARN]:        at com.google.gson.Gson.fromJson(Gson.java:803) 
[17:17:53 WARN]:        at com.google.gson.Gson.fromJson(Gson.java:768) 
[17:17:53 WARN]:  
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 2 column 4 
[17:17:53 WARN]:        at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:374) 
[17:17:53 WARN]:        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:165) 
[17:17:53 WARN]:        ... 18 more

待读取的JSON文件内容如下:

{
  "WorldName:world X:-3 Z:-64": {
    "WorldName:world X:-39 Y:63 Z:-1016": {
      "filteredMaterials": [
        "ROTTEN_FLESH"
      ],
      "chestType": "DOUBLE"
    },
    "WorldName:world X:-40 Y:63 Z:-1016": {
      "filteredMaterials": [
        "ROTTEN_FLESH"
      ],
      "chestType": "DOUBLE"
    }
  }
}

恢复方法代码:

private void recoverCollectionChests() {
    final File file = new File(getDataFolder(), "chests.json");

    if(file.exists() && file.length() > 2) {
        try {
            final Gson gson = new GsonBuilder().setPrettyPrinting().create();
            final Type type = new TypeToken<Map<Chunk, LinkedHashMap<Location, ChestObject>>>() {}.getType();
            final Map<Chunk, LinkedHashMap<Location, ChestObject>> map = gson.fromJson(new FileReader(file), type);
            System.out.println("Map: " + map);
        } catch (IllegalStateException | JsonSyntaxException | IOException e) {
            e.printStackTrace();
        }
    }
}

保存方法代码:

private void saveChests() {
    try {
        if(!CHEST_MAP.isEmpty()) {
            final File file = new File(this.getDataFolder(), "chests.json");
            final Gson gson = new GsonBuilder().setPrettyPrinting().create();
            final Writer writer = new FileWriter(file);

            gson.toJson(CHEST_MAP, writer);
            writer.flush();
            writer.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

请问该异常的具体原因是什么?


异常原因分析

核心问题出在Gson对Map自定义类型键的默认序列化/反序列化逻辑不匹配:

  1. 序列化阶段:Gson处理Map的自定义对象键(Chunk、Location)时,不会将其序列化为标准的对象结构({...}形式),而是直接调用对象的toString()方法,把键转成了字符串(也就是你JSON里看到的"WorldName:world X:-3 Z:-64"这类内容),这也是保存操作能正常完成的原因。

  2. 反序列化阶段:Gson识别到目标类型是Map<Chunk, ...>后,会默认尝试把JSON中的键解析为Chunk对象——也就是期望读取一个对象的起始标记{(BEGIN_OBJECT),但实际读到的是字符串类型的键,两者不匹配,就抛出了Expected BEGIN_OBJECT but was STRING的异常。

简单来说,序列化时把自定义对象键转成了字符串,但反序列化时Gson不知道要把这个字符串转回对应的自定义对象,反而当成对象结构来解析,最终导致格式不兼容。


内容的提问来源于stack exchange,提问作者HowDoISolveThis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:50:16