json - 将 hashmap 转换为 JSON 对象时从 Gson 获取 stackoverflowerror

标签 json hashmap gson

我想将树结构中的数据表示为 java 对象,然后我想将其转换为 JSON 对象。

借助 stackoverflow 条目:

Convert java arrayList of Parent/child relation into tree?

hashmap to JSON using GSON

我有下面的主要功能和“对”列表包含一对: child 和 parent

ArrayList<Pair> list= new ArrayList<>();
list.add(new Pair("6", "4"));
list.add(new Pair("5", "4"));
list.add(new Pair("4", "3"));
list.add(new Pair("2", "3"));
list.add(new Pair("3", "null"));

Map<String, Node> o_map= new HashMap<>();
for (Pair l: list) {
Node parent = o_map.getOrDefault(l.getParentId(), new Node(l.getParentId()));
Node child = o_map.getOrDefault(l.getChildId(), new Node(l.getChildId()));
parent.children.add(child);
child.parent = parent;
o_map.put(parent.id, parent);
o_map.put(child.id, child);
}
Gson gs = new Gson();
System.out.println(gs.toJson(o_map));
}

但是这段代码返回:

Exception in thread "main" java.lang.StackOverflowError
    at java.io.StringWriter.write(StringWriter.java:112)
    at com.google.gson.stream.JsonWriter.string(JsonWriter.java:576)
    at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:402)
    at com.google.gson.stream.JsonWriter.beginArray(JsonWriter.java:287)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:95)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)

错误。

我不明白为什么会返回这样的错误。 可能是什么原因? 非常感谢您。

最佳答案

您没有包含您的 Node类定义,但我猜它看起来像这样:

public class Node {
  public final String id;
  public Node parent;
  public final ArrayList<Node> children = new ArrayList<>();

  public Node(String id) {
    this.id = id;
  }
}

这是在内存中 表示树数据结构的好方法(忽略一些不相关的样式问题,例如使用公共(public)字段),但无法序列化。为什么?因为任何 Node使用非空 parent具有循环关系 - 子项包含对其父项的引用,而父项又包含对子项的引用,而子项又包含对父项的引用,而父项又包含......

来自user guide :

Note that you can not serialize objects with circular references since that will result in infinite recursion.

我们可以用这个更简单的例子触发同样的错误:

Node root = new Node("A");
Node child = new Node("B");
root.children.add(child);
child.parent = root;
System.out.println(new Gson().toJson(root)); // passing in child would similarly fail

那么我们如何解决这个问题呢?这取决于你想要什么样的行为。一个简单的选择是阻止 Gson 尝试序列化 parent字段(我们不需要它,因为我们可以从 children 列表中重建它)。为此只需 mark parent as transient 而 Gson 不会将其包含在结果中。您可以类似地制作 children transient如果明确记录父关系更有帮助,则字段。序列化 children 的好处然而,字段是你可以只传入根节点,整个树将被遍历。

另一种选择是序列化与 Map<String, Node> 不同的数据结构。 - 你目前正在将每个节点 ID 映射到它的 Node对象(它可传递地包含对每个其他节点的引用),这意味着即使您修复了循环关系,您仍然会得到一些奇怪的 JSON 作为结果。 似乎您真正想要的只是序列化 ID -> parent 或 ID -> children 关系,这将是 Map<String, String>Map<String, List<String>> Gson 可以轻松序列化的数据结构。如果那是你想要的结构,你可以简单地遍历你的树并首先构造这样的数据结构,或者定义一个 custom deserializer转换 Node转换成您想要的确切 JSON 结构。

关于json - 将 hashmap 转换为 JSON 对象时从 Gson 获取 stackoverflowerror,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40079530/

相关文章:

c# - JSON 字符串到 C# 中的模型/HashMap/字典

google-app-engine - GAE 数据存储 : can't get UTF-8 to work as default encoding

java - 使用改造转换特殊 JSON 响应

php - 使用 Json 传递两个查询

java - HashMap 中的 ArrayList<Object> 之谜

java - HashMap#hash(int)方法的解释

java - 使用 Gson 从 List 对象数据转换为 JSON 数据时日期时间格式发生变化

javascript - 使用 javascript 设置 Coldfusion 变量以便在同一页面上的 Replace() 中使用?

java - 在 smartGWT 的 Listgrid 中渲染嵌套 JSON 字符串

javascript - 如何在 Electron renderer.js 文件中使用 Node.js 解析 JSON?