使用抽象类对多图进行Gson反序列化

时间:2018-11-13 21:15:02

标签: java json serialization gson deserialization

我无法为自己的生活弄清楚如何反序列化:

NSUserActivity

放入{PetPlayer中的INInteraction中,其中包含一个称为“ pets”的多图,结构如下: { "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" } } 。 PetType是此处的枚举,而Pet是具有多个实现的抽象类。

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

第一:     公共最终类HashMultimapAdapter实现JsonSerializer>,JsonDeserializer> {         私有静态最终PetAdapter petAdapter = new PetAdapter();

Map<UUID, PetPlayer>

第二:

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; } }

非常感谢您的帮助:)

1 个答案:

答案 0 :(得分:0)

我真的不知道如何用gson做到这一点,而无需手动或hacky。太大了,不能发表评论,因此我将其留在这里作为答案,以帮助您解决问题。

首先,由于在相同参数上调用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实现不依赖于其他自定义序列化器/反序列化器。就像您可以想象的那样,这确实很麻烦。

另一种方法是手动反序列化。这意味着您将必须遍历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*/);
   }
}

希望这会有所帮助。