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

我一生都无法弄清楚如何反序列化:


{

  "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"]


我非常感谢任何帮助:)


牧羊人nacy
浏览 151回答 1
1回答

青春有我

我真的不知道在没有手动或hacky的情况下使用gson执行此操作的方法。这太大了,无法作为评论发表,因此我将其留在这里作为答案,以帮助您解决问题。首先,您会遇到堆栈溢出,因为您正在调用context.deserialize相同的参数,这些参数触发gson调用相同的反序列化器,它将再次调用context.deserialize,依此类推,直到堆栈溢出。序列化时你会遇到同样的问题,因为你也只是在做context.serialize.为避免这种情况,您需要避免gson递归调用序列化器/反序列化器的方法。这很容易通过创建另一个gson没有适配器的实例来实现:public class PetAdapter&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;implements JsonSerializer<Pet>, JsonDeserializer<Pet> {&nbsp; private final Gson gson = new Gson();&nbsp; @Override&nbsp; public Pet deserialize(JsonElement jsonElement, Type typeOfT,&nbsp;&nbsp; &nbsp; &nbsp; JsonDeserializationContext context) throws JsonParseException {&nbsp; &nbsp; &nbsp;EntityType entityType = EntityType.valueOf(jsonElement.getAsJsonObject().get("entityType").getAsString());&nbsp; &nbsp; &nbsp; switch (entityType) {&nbsp; &nbsp; &nbsp; &nbsp; case IRON_GOLEM:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return gson.fromJson(jsonElement, EcoPet.class);&nbsp; &nbsp; &nbsp; &nbsp; case WOLF:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return gson.fromJson(jsonElement, BoostPet.class);&nbsp; &nbsp; &nbsp; &nbsp; case MAGMA_CUBE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return gson.fromJson(jsonElement, CombatPet.class);&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new JsonParseException("Invalid PetType");&nbsp; &nbsp; &nbsp; }&nbsp; }&nbsp; @Override&nbsp; public JsonElement serialize(Pet src, Type typeOfSrc, JsonSerializationContext context) {&nbsp; &nbsp; return gson.toJson(src);&nbsp; }}这有效,但前提是您的Pet实现不依赖于其他自定义序列化器/反序列化器。所以你可以想象这很hacky。另一种方法是手动反序列化。这意味着您必须通过 json 元素并读取属性,就像您正在阅读entityType和手动构建您的对象一样。非常相似,我想(我没有检查这个),您可以首先context将每个宠物反序列化为一个Map对象,并让每个宠物实现一个静态方法,该方法从该地图创建特定宠物的实例。就像是:public class IronGolem extends Pet {&nbsp; &nbsp;public static IronGolem from(Map<String, Object> deserializedPet) {&nbsp; &nbsp; &nbsp; // here check the map for each thing you need&nbsp; &nbsp; &nbsp; return new IronGolem(/*pass in every attribute*/);&nbsp; &nbsp;}}希望这可以帮助。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java