gson.toJson () lanza StackOverflowError

Me gustaría generar una cadena JSON desde mi objeto:

Gson gson = new Gson(); String json = gson.toJson(item); 

Cada vez que trato de hacer esto, obtengo este error:

 14:46:40,236 ERROR [[BomItemToJSON]] Servlet.service() for servlet BomItemToJSON threw exception java.lang.StackOverflowError at com.google.gson.stream.JsonWriter.string(JsonWriter.java:473) at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:347) at com.google.gson.stream.JsonWriter.value(JsonWriter.java:440) at com.google.gson.internal.bind.TypeAdapters$7.write(TypeAdapters.java:235) at com.google.gson.internal.bind.TypeAdapters$7.write(TypeAdapters.java:220) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60) at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:843) 

Estos son los atributos de mi clase BomItem :

 private int itemId; private Collection modules; private boolean deprecated; private String partNumber; private String description; //LOB private int quantity; private String unitPriceDollar; private String unitPriceEuro; private String discount; private String totalDollar; private String totalEuro; private String itemClass; private String itemType; private String vendor; private Calendar listPriceDate; private String unitWeight; private String unitAveragePower; private String unitMaxHeatDissipation; private String unitRackSpace; 

Atributos de mi clase de BomModule referenciada:

 private int moduleId; private String moduleName; private boolean isRootModule; private Collection parentModules; private Collection subModules; private Collection items; private int quantity; 

¿Alguna idea de lo que causa este error? ¿Cómo puedo arreglarlo?

Ese problema es que tienes una referencia circular.

En la clase BomModule , hace referencia a:

 private Collection parentModules; private Collection subModules; 

Esa referencia a BomModule , obviamente, no le gustó GSON en absoluto.

Una solución alternativa es establecer los módulos en null para evitar el bucle recursivo. De esta forma puedo evitar el StackOverFlow-Exception.

 item.setModules(null); 

O marque los campos que no desea que aparezcan en el json serializado utilizando la palabra clave transient , por ejemplo:

 private transient Collection parentModules; private transient Collection subModules; 

Tuve este problema cuando tenía un registrador Log4J como propiedad de clase, como por ejemplo:

 private Logger logger = Logger.getLogger(Foo.class); 

Esto puede resolverse haciendo el registrador static o simplemente moviéndolo a la (s) función (es) real (es).

Como dijo SLaks, StackOverflowError ocurre si tiene una referencia circular en su objeto.

Para solucionarlo, podría usar TypeAdapter para su objeto.

Por ejemplo, si solo necesita generar String desde su objeto, podría usar un adaptador como este:

 class MyTypeAdapter extends TypeAdapter { public T read(JsonReader reader) throws IOException { return null; } public void write(JsonWriter writer, T obj) throws IOException { if (obj == null) { writer.nullValue(); return; } writer.value(obj.toString()); } } 

y registrarlo así:

 Gson gson = new GsonBuilder() .registerTypeAdapter(BomItem.class, new MyTypeAdapter()) .create(); 

o de esta manera, si tiene una interfaz y desea usar el adaptador para todas sus subclases:

 Gson gson = new GsonBuilder() .registerTypeHierarchyAdapter(BomItemInterface.class, new MyTypeAdapter()) .create(); 

Si está usando Realm y obtiene este error, y el objeto que causa el problema extiende RealmObject, no olvide hacer realm.copyFromRealm(myObject) para crear una copia sin todos los enlaces Realm antes de pasar a GSON para la serialización.

Me había perdido haciendo esto solo por uno de los objetos que se están copiando … me llevó años darme cuenta ya que el seguimiento de la stack no nombra la clase / tipo de objeto. La cuestión es que el problema está causado por una referencia circular, pero es una referencia circular en algún lugar de la clase base RealmObject, no su propia subclase, ¡lo que hace que sea más difícil de detectar!

Mi respuesta es un poco tarde, pero creo que esta pregunta aún no tiene una buena solución. Lo encontré originalmente aquí .

Con Gson puedes marcar los campos que deseas que se incluyan en json con @Expose así:

 @Expose String myString; // will be serialized as myString 

y crea el objeto gson con:

 Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); 

Referencias circulares que simplemente no expone. ¡Eso hizo el truco para mí!

Este error es común cuando tienes un registrador en tu súper clase. Como antes sugirió @Zar, puede usar estática para su campo de registro, pero esto también funciona:

 protected final transient Logger logger = Logger.getLogger(this.getClass()); 

PS probablemente funcione y con la anotación @Expose, consulte más sobre esto aquí: https://stackoverflow.com/a/7811253/1766166

Tengo el mismo problema. En mi caso, el motivo fue que el constructor de mi clase serializada tomó una variable de contexto, como esta:

 public MetaInfo(Context context) 

Cuando elimino este argumento, el error desapareció.

 public MetaInfo() 

En Android, gson stack overflow resultó ser la statement de un Handler. Lo movió a una clase que no se está deserializando.

En base a la recomendación de Zar, establecí el controlador estático cuando esto sucedió en otra sección del código. Hacer el controlador estático funcionó también.

BomItem refiere a BOMModule ( BOMModule Collection modules ) y BOMModule refiere a BOMItem (elementos de Collection items ). A la biblioteca Gson no le gustan las referencias circulares. Elimina esta dependencia circular de tu clase. Yo también había tenido el mismo problema en el pasado con gson lib.

Tuve este problema para mí cuando puse:

 Logger logger = Logger.getLogger( this.getClass().getName() ); 

en mi objeto … ¡lo cual tiene mucho sentido después de una hora más o menos de depuración!

Editar: Lo siento por mi mal, esta es mi primera respuesta. Gracias por tus consejos.

Creo mi propio convertidor Json

La solución principal que utilicé fue crear un conjunto de objetos padres para cada referencia de objeto. Si una subreferencia apunta a un objeto padre existente, se descartará. Luego combino con una solución extra, limitando el tiempo de referencia para evitar el bucle infinitivo en una relación bidireccional entre entidades.

Mi descripción no es muy buena, espero que les sirva de ayuda.

Esta es mi primera contribución a la comunidad Java (solución a su problema). Puede verificarlo;) Hay un archivo README.md https://github.com/trannamtrung1st/TSON