2016-10-17 108 views
1

我想將樹形結構中的數據表示爲java對象,然後我想將其轉換爲JSON對象。在將hashmap轉換爲JSON對象時從Gson獲取stackoverflowerror

隨着計算器項目的幫助:

Convert java arrayList of Parent/child relation into tree?

hashmap to JSON using GSON

我有以下主要功能和 「雙」 列表中包含一對:孩子和家長

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) 

錯誤。

我不明白爲什麼它會返回這樣的錯誤。 可能是什麼原因? 非常感謝您提前。

+0

我需要做的是將hashmap >轉換爲json對象。 – nenana

+0

你不應該寫這樣的'ArrayList list = new ArrayList ();' – Mark

+0

我需要在json中有樹結構。爲此,我需要將hashmap轉換爲json。我嘗試了另一種方法,爲json寫了一個雙列表,但結果並不是我所期待的。 – nenana

回答

1

你沒有包括您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; 
    } 
} 

這是在內存中表示樹數據結構罰款的方式(忽略了一些無關的風格問題,如使用公共字段),但是不可能序列化。爲什麼?因爲具有非空parent的任何Node都有一個循環關係 - 一個孩子包含對其父代的引用,而該引用又包含對該孩子的引用,該引用又包含對父代的引用,該引用又包含... ..

user guide

請注意,您不能序列循環引用的對象,因爲這將導致無窮遞歸。

我們可以觸發這個簡單的例子同樣的錯誤:

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不會在結果中包括它。如果顯式記錄父親關係更有幫助,您也可以同樣製作childrentransient字段。然而,序列化children字段的好處是,您只需傳入根節點並遍歷整個樹。

另一種選擇是序列不同的數據結構比Map<String, Node> - 您目前映射每個節點ID到它的Node對象(其傳遞地,包含於每一個其他節點的引用),這意味着即使你固定的週期性關係,你仍然會得到一些奇怪的JSON。它似乎像你真正想要的只是序列化ID - >父母或身份證 - >兒童關係,這將是一個Map<String, String>Map<String, List<String>>數據結構,Gson將沒有麻煩序列化。如果這是你想要的結構,你可以簡單地遍歷你的樹並首先構造這樣一個數據結構,或者定義一個custom deserializer,它將Node轉換爲你想要的確切JSON結構。