在将hashmap转换为JSON对象的同时从Gson获取stackoverflowerror [英] Getting stackoverflowerror from Gson while converting hashmap to JSON object
问题描述
在stackoverflow条目的帮助下:
我有下面的主函数和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?
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屋!