fromjson - gson java
Obteniendo stackoverflowerror de Gson al convertir hashmap en objeto JSON (1)
No incluyó su definición de clase Node
, pero supongo que se parece a esto:
public class Node {
public final String id;
public Node parent;
public final ArrayList<Node> children = new ArrayList<>();
public Node(String id) {
this.id = id;
}
}
Esta es una excelente forma de representar una estructura de datos de árbol en la memoria (ignorando algunos problemas de estilo no relacionados como el uso de campos públicos), pero es imposible serializarla. ¿Por qué? Como cualquier Node
con un elemento parent
no nulo tiene una relación cíclica, un elemento secundario contiene una referencia a su elemento principal, que a su vez contiene una referencia al elemento secundario, que a su vez contiene una referencia al elemento primario, que a su vez contiene ... ..
Tenga en cuenta que no puede serializar objetos con referencias circulares ya que eso dará como resultado una recursión infinita.
Podemos desencadenar el mismo error con este ejemplo más simple:
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
Entonces, ¿cómo podemos arreglar esto? Depende del comportamiento que desee. Una opción fácil es evitar que Gson intente serializar el campo parent
(no lo necesitamos, ya que podemos reconstruirlo desde la lista de children
). Para hacer esto, simplemente marque parent
como transient
y Gson no lo incluirá en el resultado. De manera similar, puede hacer que los children
el campo transient
si la grabación explícita de la relación principal es más útil. Sin embargo, una ventaja de serializar el campo de children
es que puede pasar el nodo raíz y se recorrerá todo el árbol.
Otra opción es serializar una estructura de datos diferente a Map<String, Node>
: actualmente está asignando cada ID de nodo a su objeto Node
(que, transitivamente, contiene una referencia a cada otro nodo), lo que significa que incluso si repara el relación cíclica, todavía obtendrás un JSON extraño como resultado. Parece que lo que realmente quieres es serializar las relaciones ID -> parent o ID -> children, que serían una estructura de datos Map<String, String>
o Map<String, List<String>>
que Gson no tiene problemas para serializar. Si esa es la estructura que desea, simplemente podría atravesar su árbol y construir tal estructura de datos primero, o definir un deserializador personalizado que convierta un Node
en la estructura JSON exacta que desee.
Quiero representar los datos en la estructura de árbol como objeto java y luego quiero convertirlo a objeto JSON.
Con la ayuda de las entradas de stackoverflow:
Convertir java arrayList de la relación padre / hijo en el árbol?
Tenía abajo la función principal y la lista de "pares" contiene un par: hijo y padre
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));
}
Sin embargo, este código regresa:
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.
No entiendo por qué devuelve ese error. ¿Cuál podría ser la razón? Muchas gracias por adelantado.