【问题标题】:gson serialization and deserialization of an ArrayList<object>ArrayList<object> 的 gson 序列化和反序列化
【发布时间】:2014-04-24 03:45:39
【问题描述】:

我的设置是这样的:

public enum AnimalType {
  CAT(1),
  DOG(2);

  private final int value;
  AnimalType(int value) {
    this.value = value;
  }
  public int value() { return value; }
}

public class Dog {
  AnimalType type = AnimalType.DOG;
  String name;
  int id;
  //Other properties. Point is to distinguish it from a Cat object.
}

public class Cat {
  AnimalType type = AnimalType.CAT;
  String name;
  String nickName;
  int age;
}

public class Response {
  ArrayList<Object> myResponseObject;
}

这是一个 Response 对象的外观示例:

ArrayList<Object> arr = new ArrayList<Object>();
Dog dog = new Dog("MyName",0);
Cat cat = new Cat("MyName","MyNickName",-1);

arr.add("I have a ");
arr.add(cat)
arr.add(" and a ");
arr.add(dog)
Response response = new Response(arr);

我是这样序列化的:

Gson gson = new Gson();
String serializedOutput = gson.toJson(response);

并希望像这样反序列化:

//the ArrayList<Object> should be populated correctly inside of it?
Response deserializedObject = gson.fromJson(serializedOutput);

但是,在反序列化此列表时,我需要将对象映射回它们各自的类型。我怀疑我至少需要将类或类型标记到我的 Dog 或 Cat 序列化中。现在,我在 Dog 和 Cat 上添加一个 Type 属性(而不是接口)。

没有任何花哨的东西,CatDog 对象在反序列化时默认被视为LinkedTreeMap&lt;K,V&gt;。我必须遍历我的arraylist,检查它是否是LinkedTreeMap 的实例,调用“type”键来获取类型,然后将我的对象转换为Dog 或Cat。这一切对我来说似乎有点老套,我想知道是否有更优雅的方法来做到这一点。

我应该为我的 Cat/Dog 对象使用自定义序列化器/反序列化器,还是应该使用 RuntimeTypeAdapterFactory?任何指导将不胜感激。

注意,我还按照Gson: How to change output of Enum 的指示自定义序列化/反序列化我的枚举。我不确定这是否会影响任何事情。

谢谢

【问题讨论】:

  • 正如您在下面提到的,您要发布您的解决方案吗?
  • 是的,我会的。抱歉耽搁了。一直很忙。我犹豫是否按原样处理它的原因是因为我的解决方案并不像我希望的那样干净。我不喜欢发布没有明确描述/解释 * 的答案。
  • 我明白了。谢谢。

标签: java gson


【解决方案1】:

用户指南中对此进行了介绍。您正在尝试deserialize a collection of arbitrary types

如上所述,您有 3 个选项:

选项 1:使用 Gson 的解析器 API(低级流解析器或 DOM parser JsonParser) 来解析数组元素,然后使用 Gson.fromJson() 在每个数组元素上。这是首选 方法。

选项 2:为 Collection.class 注册一个类型适配器,它查看 每个数组成员并将它们映射到适当的对象。这 这种方法的缺点是它会搞砸反序列化 Gson 中的其他集合类型。

选项 3:为 MyCollectionMemberType 注册一个类型适配器并使用 fromJson 和 Collection 这种方法是 仅当数组作为*元素出现或者如果您 可以将保存集合的字段类型更改为类型 集合

在谈到自动反序列化时,这是一个难题。此外,选项 3 在您的情况下是不可能的,因为您使用的是 Object 而不是从某些基类(例如 Animal)继承 DogCat

最重要的是......你正在对那个对象数组做一些非常奇怪的事情,也将Strings 粘贴在其中。总的来说,如果这是你自己产生的一些反应……我会认真地重新考虑你是如何处理这个问题的。

【讨论】:

  • 是的,我现在确实有一个解决方案。我会尽量在本周末之前以清晰的格式发布它。我最终混合使用了 TypeAdapter 和自定义反序列化器。但是,我坚持使用 ArrayList 而不是集合集。
  • ArrayList is Collection ;) 他们只是笼统地说。
  • 集合更通用,对吗?我想我只是想强调订单被保留了,收藏并没有固有地让我觉得保留了秩序(听起来更像是一套)。但你是对的。