gson.toJson () lancia StackOverflowError

Vorrei generare una stringa JSON dal mio object:

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

Ogni volta che provo a farlo, ottengo questo errore:

 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) 

Questi sono gli attributi della mia class 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; 

Attributi della mia class BomModule di riferimento:

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

Qualche idea su cosa causa questo errore? Come posso ripararlo?

    Il problema è che hai un riferimento circolare.

    Nella class BomModule ti riferisci a:

     private Collection parentModules; private Collection subModules; 

    Quell’auto riferimento a BomModule , ovviamente, non è affatto piaciuto a GSON.

    Una soluzione alternativa è semplicemente impostare i moduli su null per evitare il ricorsivo looping. In questo modo posso evitare l’eccezione StackOverFlow.

     item.setModules(null); 

    O segna i campi che non vuoi mostrare nella versione serializzata usando la parola chiave transient , ad esempio:

     private transient Collection parentModules; private transient Collection subModules; 

    Ho avuto questo problema quando avevo un logger Log4J come proprietà di class, come ad esempio:

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

    Questo può essere risolto rendendo il logger static o semplicemente spostandolo nelle funzioni effettive.

    Come ha detto SLaks, StackOverflowError si verifica se hai un riferimento circolare nel tuo object.

    Per risolvere il problema potresti usare TypeAdapter per il tuo object.

    Ad esempio, se è necessario generare solo String dal proprio object, è ansible utilizzare un adattatore come questo:

     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()); } } 

    e registralo in questo modo:

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

    o così, se hai un’interfaccia e vuoi usare l’adattatore per tutte le sue sottoclassi:

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

    Se stai usando Realm e ottieni questo errore, e l’object che dà il problema estende RealmObject, non dimenticare di fare realm.copyFromRealm(myObject) per creare una copia senza tutti i binding di Realm prima di passare a GSON per la serializzazione.

    Mi ero perso a farlo solo per uno tra un mucchio di oggetti copiati … mi ci sono voluti anni per rendermi conto che la traccia dello stack non nominava la class / tipo di object. Il problema è che il problema è causato da un riferimento circolare, ma si tratta di un riferimento circolare da qualche parte nella class base RealmObject, non nella propria sottoclass, che rende più difficile da individuare!

    La mia risposta è un po ‘in ritardo, ma penso che questa domanda non abbia ancora una buona soluzione. L’ho trovato originariamente qui .

    Con Gson puoi segnare i campi che vuoi essere inclusi in json con @Expose come questo:

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

    e crea l’object gson con:

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

    Riferimenti circolari che non si espongono. Questo ha fatto il trucco per me!

    Questo errore è comune quando hai un logger nella tua super class. Come suggerito in precedenza da @Zar, puoi utilizzare la statica per il campo del tuo logger, ma funziona anche:

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

    PS probabilmente funzionerà e con l’annotazione @Expose controlla di più su questo qui: https://stackoverflow.com/a/7811253/1766166

    Ho lo stesso problema. Nel mio caso la ragione era che il costruttore della mia class serializzata prendeva una variabile di contesto, come questa:

     public MetaInfo(Context context) 

    Quando elimino questo argomento, l’errore è andato.

     public MetaInfo() 

    In Android, l’overflow dello stack gson si è rivelato la dichiarazione di un gestore. L’ho spostato in una class che non viene deserializzata.

    Sulla base della raccomandazione di Zar, ho reso il gestore statico quando questo è accaduto in un’altra sezione di codice. Anche la statica del gestore ha funzionato.

    BomItem fa riferimento a BOMModule ( Collection modules ) e BOMModule fa riferimento a BOMItem (elementi Collection items ). La libreria Gson non ama i riferimenti circolari. Rimuovi questa dipendenza circolare dalla tua class. Anch’io ho dovuto affrontare lo stesso problema in passato con lib libiche.

    Ho avuto questo problema per me quando ho messo:

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

    nel mio object … che aveva perfettamente senso dopo circa un’ora di debugging!

    Edit: Scusa per il mio male, questa è la mia prima risposta. Grazie per i tuoi consigli.

    Creo il mio JSON Converter

    La soluzione principale che ho usato è creare un insieme di oggetti genitori per ogni riferimento a un object. Se un sotto-riferimento punta all’object genitore esistente, verrà scartato. Poi combino con una soluzione extra, limitando il tempo di riferimento per evitare il loop infinito nella relazione bidirezionale tra entity framework.

    La mia descrizione non è buona, spero che ti aiuti ragazzi.

    Questo è il mio primo contributo alla comunità Java (soluzione al tuo problema). Puoi verificarlo;) C’è un file README.md https://github.com/trannamtrung1st/TSON