在将hashmap转换为JSON对象的同时从Gson获取stackoverflowerror [英] Getting stackoverflowerror from Gson while converting hashmap to JSON object

查看:458
本文介绍了在将hashmap转换为JSON对象的同时从Gson获取stackoverflowerror的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



在stackoverflow条目的帮助下:

将父/子关系的java arrayList转换为树?





我有下面的主函数和pairs列表包含一对:child和parent

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

地图< 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));
}

然而,这段代码会返回:

 线程main中的异常java.lang.StackOverflowError $ b $在java.io.StringWriter.write(StringWriter.java:112)
at com。 google.gson.stream.JsonWriter.string(JsonWriter.java:576)
位于com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:402)
位于com.google.gson。 stream.JsonWriter.beginArray(JsonWriter.java:287)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory $ Adapter.write(CollectionTypeAdapterFactory.java:95)
com.google.gson。 internal.bind.CollectionTypeAdapterFactory $ Adapter.write(CollectionTypeAdapterFactory.java:61)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
com.google。 gson.internal.bind.ReflectiveTypeAdapterFactory $ 1.write(ReflectiveTypeAdapterFactory.java:112)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactor y $ 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;




$ b

这是一种很好的方式来表示树形数据结构在内存中<忽略一些不相关的样式问题(如使用公共字段),但不可能序列化。为什么?由于任何 Node 与非空父具有循环关系 - 子项包含对其父项的引用,反过来又包含对孩子的引用,而孩子又包含对父代的引用,而该引用又包含.....



用户指南


请注意,您不能使用循环引用序列化对象,因为这会导致无限递归。


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

 节点root =新节点(A); 
节点child =新节点(B);
root.children.add(child);
child.parent = root;
System.out.println(new Gson()。toJson(root)); //传入孩子同样会失败

那么我们该如何解决这个问题呢?这取决于你想要的行为。一个简单的选择是阻止Gson试图序列化字段(我们不需要它,因为我们可以从 children 列表)。只需父母标记为 transient ,Gson不会将其包含在结果中。如果显式记录父亲关系更有帮助,您可以同样使 children transient 字段。然而,序列化 children 字段的好处是你可以传入根节点并遍历整个树。



另一种选择是序列化不同于 Map< String,Node> 的数据结构 - 您当前将每个节点ID映射到它的 Node 对象(它在传递中包含对每个其他节点的引用),这意味着即使您修复了循环关系,您仍然会得到一些奇怪的JSON。它似乎像你想要的只是序列化ID - >父或ID - >子关系,它将是一个 Map< String,String> 映射<字符串,列表< String>> 数据结构,Gson在序列化时没有问题。如果这是你想要的结构,你可以简单地遍历你的树并首先构造这样一个数据结构,或者定义一个自定义反序列化器,它将 Node 转换为您想要的确切JSON结构。


I want to represent data in tree structure as java object then I want to convert it to JSON object.

With the help of stackoverflow entries:

Convert java arrayList of Parent/child relation into tree?

hashmap to JSON using GSON

I had below main function and "pairs" list contains a pair: child and 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));
}

However this code returns:

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)

error.

I don't get why it returns such an error. What could be the reason? Thank you very much in advance.

解决方案

You didn't include your Node class definition, but I'm guessing it looks something like this:

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

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

This is a fine way to represent a tree data structure in memory (ignoring some unrelated style issues like using public fields), but it's impossible to serialize. Why? Because any Node with a non-null parent has a cyclical relationship - a child contains a reference to its parent, which in turn contains a reference to the child, which in turn contains a reference to the parent, which in turn contains .....

From the user guide:

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

We can trigger the same error with this simpler example:

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

So how can we fix this? It depends on what behavior you want. One easy option is to prevent Gson from attempting to serialize the parent field (we don't need it, as we can reconstruct it from the children list). To do this just mark parent as transient and Gson will not include it in the result. You could similarly make children the transient field if explicitly recording the parent relationship is more helpful. A benefit of serializing the children field however is that you can just pass in the root node and the whole tree will be traversed.

Another option is to serialize a different data structure than Map<String, Node> - you're currently mapping each node ID to its Node object (which, transitively, contains a reference to every other node), meaning that even if you fix the cyclical relationship you're still going to get some odd JSON as a result. It seems like what you'd really want is to just serialize the ID -> parent or ID -> children relationships, which would be a Map<String, String> or Map<String, List<String>> data structure which Gson will have no trouble serializing. If that's the structure you want you could simply traverse your tree and construct such a data structure first, or define a custom deserializer which converts a Node into the exact JSON structure you want.

这篇关于在将hashmap转换为JSON对象的同时从Gson获取stackoverflowerror的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆