为了账号安全,请及时绑定邮箱和手机立即绑定

具有抽象类的多映射的 Gson 反序列化

具有抽象类的多映射的 Gson 反序列化

牧羊人nacy 2022-01-19 16:54:57
我一生都无法弄清楚如何反序列化:{  "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"  }}进入一个Map<UUID, PetPlayer>带有 PetPlayer 的包含一个名为“pets”的多图,其结构如下;Multimap<PetType, Pet>. PetType 在这里是一个枚举,而 Pet 是一个具有多个实现的抽象类。我尝试使用这两个序列化器和反序列化器。第一:public final class HashMultimapAdapter implements JsonSerializer>, JsonDeserializer> { private static final PetAdapter petAdapter = new PetAdapter();    @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;    }}这导致了堆栈溢出。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 回答

?
青春有我

TA贡献1784条经验 获得超8个赞

我真的不知道在没有手动或hacky的情况下使用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实现不依赖于其他自定义序列化器/反序列化器。所以你可以想象这很hacky。


另一种方法是手动反序列化。这意味着您必须通过 json 元素并读取属性,就像您正在阅读entityType和手动构建您的对象一样。


非常相似,我想(我没有检查这个),您可以首先context将每个宠物反序列化为一个Map对象,并让每个宠物实现一个静态方法,该方法从该地图创建特定宠物的实例。就像是:


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*/);

   }

}

希望这可以帮助。


查看完整回答
反对 回复 2022-01-19
  • 1 回答
  • 0 关注
  • 150 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信