当前位置: 首页 > 知识库问答 >
问题:

具有抽象类的multimap的Gson反序列化

严嘉良
2023-03-14

我一辈子都想不出如何反序列化这一点:

{
  "c8147c8a-09c3-4165-b5c2-ce72e2c97100": {
    "pets": {
      "BOOST": [
        {
          "mcmmoBoost": 15.0,
          "owner": "c8147c8a-09c3-4165-b5c2-ce72e2c97100",
          "entityType": "IRON_GOLEM",
          "health": 150.0,
          "tier": 1,
          "alive": true
        }
      ]
    },
    "uuid": "c8147c8a-09c3-4165-b5c2-ce72e2c97100"
  }
}

映射 ,其中PetPlayer包含一个名为“pets”的多映射,结构如下;multimap 。这里,PetType是枚举,Pet是一个抽象类,具有多个实现。

我尝试使用这两个序列化器和反序列化器。

    @Override
    public JsonElement serialize(Multimap<PetType, Pet> src, Type typeOfSrc, JsonSerializationContext context) {
        return context.serialize(src.asMap());
    }

    @Override
    public Multimap<PetType, Pet> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Map<PetType, Collection<JsonElement>> asMap = context.deserialize(json, new TypeToken<Map<PetType, Collection<JsonElement>>>(){{}}.getType());
        Multimap<PetType, Pet> multimap = ArrayListMultimap.create();

        for (Map.Entry<PetType, Collection<JsonElement>> entry : asMap.entrySet()) {
            entry.getValue().forEach(jsonElement -> {
                multimap.put(entry.getKey(), petAdapter.deserialize(jsonElement, Pet.class, context));
            });
        }

        return multimap;
    }
}
public class PetAdapter implements JsonSerializer<Pet>, JsonDeserializer<Pet> {
    @Override
    public Pet deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        EntityType entityType = EntityType.valueOf(jsonElement.getAsJsonObject().get("entityType").getAsString());

        switch (entityType) {
            case IRON_GOLEM:
                return context.deserialize(jsonElement, EcoPet.class);
            case WOLF:
                return context.deserialize(jsonElement, BoostPet.class);
            case MAGMA_CUBE:
                return context.deserialize(jsonElement, CombatPet.class);
            default:
                throw new JsonParseException("Invalid PetType");

        }
    }

    @Override
    public JsonElement serialize(Pet src, Type typeOfSrc, JsonSerializationContext context) {
        return context.serialize(src);
    }
}

java.lang.StackOverflowError at com.google.gson.internal.$gson$types.resolve($gson$types.java:375)~[paperspigot-1.8.8-r0.1.jar:git-paperspigot-“4C7641D”]

我非常感谢任何帮助:)

共有1个答案

满耀
2023-03-14

我真的不知道有什么方法可以用gson做到这一点,而不是手动或黑客。这太大了,不能把它作为一个评论,所以我把它留在这里作为一个答案,作为一个想法来帮助你。

首先,由于调用context.deserialize的参数相同,从而触发GSON调用相同的反序列化器,反序列化器将再次调用context.deserialize等,导致堆栈溢出。

在序列化时也会遇到同样的问题,因为您也只是在执行context.serialize

为了避免这种情况,您需要避免GSON递归到调用序列化程序的/反序列化程序的方法中。通过创建另一个没有适配器的GSON实例,可以非常容易地实现这一点:

public class PetAdapter 
           implements JsonSerializer<Pet>, JsonDeserializer<Pet> {
  private final Gson gson = new Gson();

  @Override
  public Pet deserialize(JsonElement jsonElement, Type typeOfT, 
      JsonDeserializationContext context) throws JsonParseException {
     EntityType entityType = EntityType.valueOf(jsonElement.getAsJsonObject().get("entityType").getAsString());

      switch (entityType) {
        case IRON_GOLEM:
            return gson.fromJson(jsonElement, EcoPet.class);
        case WOLF:
            return gson.fromJson(jsonElement, BoostPet.class);
        case MAGMA_CUBE:
            return gson.fromJson(jsonElement, CombatPet.class);
        default:
            throw new JsonParseException("Invalid PetType");
      }
  }

  @Override
  public JsonElement serialize(Pet src, Type typeOfSrc, JsonSerializationContext context) {
    return gson.toJson(src);
  }
}

这是有效的,但前提是pet实现不依赖于其他自定义序列化器/反序列化器。所以你可以想象,这是相当黑客。

另一种方法是手动反序列化。这意味着您必须像读取EntityType一样,遍历json元素并读取属性,然后手动构建对象。

public class IronGolem extends Pet {
   public static IronGolem from(Map<String, Object> deserializedPet) {
      // here check the map for each thing you need
      return new IronGolem(/*pass in every attribute*/);
   }
}
 类似资料:
  • 问题内容: 假设有一个 抽象 类say 和两个非抽象子类say 和。我想通过使用GSON库从json格式“反序列化”它们。 例如,我得到一个对象数组。 有人将其转换为JSON字符串,如下所示: 最后,如果我尝试如下反序列化 那么我就遇到了一个错误,因为GSON默认的反序列化器找到了一个抽象类(即),并且它无法猜测子类的类型。 我该如何解决? PS:我阅读了有关自定义反序列化器的信息,但在这种情况下

  • 问题内容: 我正在尝试使用Gson反序列化JSON格式的树对象。每个节点都包含其子节点作为对象类型Node的字段。Node是一个接口,具有多个具体的类实现。在反序列化过程中,如果我不知道节点属于哪种类型,那么在反序列化节点时如何与Gson沟通要实现哪个具体类?每个节点都有一个指定类型的成员字段。当对象为序列化形式时,是否有一种方法可以访问该字段,并以某种方式将该类型传达给Gson? 谢谢! 问题答

  • 假设有一个抽象类,例如和两个非抽象子类,例如和。我想使用GSON库从json格式“反序列化”它们。 例如。我得到一个对象的数组。 有人将其转换为JSON字符串,如下所示: 最后,如果我尝试反序列化如下 然后我有一个错误,因为GSON默认反序列化器找到一个抽象类(即)并且它无法猜测子类类型。 我如何解决这个问题? PS:我读过关于自定义反序列化器的文章,但我不明白如何在这种情况下使用它们。

  • 也许我跑错了方向,但我有一个元素列表,我想读。 我有一个抽象基类,让我们称之为: 现在我有两个可能的实现:

  • 我试图将JSON字符串反序列化为Java对象,但遇到以下异常: JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter@306A30C7未能对给定类型类java.util.ArrayList的json对象[“93”]进行反序列化 我的主文件: 应该表示JSON的类是: 我尝试了SO上给出的解决方案,但也有

  • 我正在尝试使用JSON ObjectMapper反序列化对象。我在尝试反序列化时看到以下错误