2012-04-18 9 views
50

Vorrei generare una stringa JSON dal mio oggetto:gson.toJson() genera StackOverflowError

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

Ogni volta che provo a fare questo, 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 BomItem classe:

private int itemId; 
private Collection<BomModule> 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 riferimento zzato BomModule classe:

private int moduleId; 
private String moduleName; 
private boolean isRootModule; 
private Collection<BomModule> parentModules; 
private Collection<BomModule> subModules; 
private Collection<BomItem> items; 
private int quantity; 

Qualsiasi idea di che cosa provoca questo errore? Come posso ripararlo?

+0

Potrebbe accadere se si inserisce un'istanza di oggetto dentro se stessa all'interno del gson. –

+0

L'eccezione perde la causa principale e avvia il registro con 'JsonWriter.java:473)', come identificare la causa principale dello stackoverflow Gson – Siddharth

risposta

52

Questo probabilmente si verifica se si dispone di un riferimento circolare.

Il numero BomModule fa riferimento all'oggetto principale?

+0

Sì un oggetto BomModule può far parte di un altro oggetto BomModule. – doonot

+0

Ma questo è un problema? 'Collection modules' è solo una raccolta e penso che gson dovrebbe essere in grado di creare un semplice array da esso? – doonot

+0

@dooonot: Qualcuno degli oggetti nella collezione fa riferimento al loro oggetto genitore? – SLaks

21

ho avuto questo problema quando avevo un registratore Log4J come struttura di classe, come ad esempio:

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

Questo può essere risolto da ciascuna rendendo logger static o semplicemente spostandolo nella funzione attuale (s).

+4

Una cattura assolutamente eccezionale Questa auto-referenza alla classe ovviamente non è piaciuta affatto a GSON Mi ha risparmiato un sacco di mal di testa ! +1 – christopher

+1

un altro modo per risolverlo, è aggiungendo il modificatore transitorio al campo – gawi

0

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

Sulla base della raccomandazione di Zar, ho effettuato l'handler statico quando ciò avveniva in un'altra sezione di codice. Anche la statica del gestore ha funzionato.

10

Come SLaks ha affermato che StackOverflowError si verifica se si dispone di un riferimento circolare nell'oggetto.

Per risolvere il problema è possibile utilizzare TypeAdapter per il proprio oggetto.

Per esempio, se avete bisogno solo di generare String dal vostro oggetto si potrebbe usare l'adattatore in questo modo:

class MyTypeAdapter<T> extends TypeAdapter<T> { 
    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 registrarlo in questo modo:

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

o come questo, se avete interfaccia e desidera utilizzare l'adattatore per tutte le sue sottoclassi:

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

Ho lo stesso problema. Nel mio caso il motivo era che il costruttore della mia variabile di contesto classe prendere serializzato, come questo:

public MetaInfo(Context context) 

Quando si elimina questa tesi, l'errore è andato.

public MetaInfo() 
+1

Ho riscontrato questo problema durante il passaggio del servizio riferimento all'oggetto come contesto. La correzione consisteva nel rendere statica la variabile di contesto nella classe che utilizza gson.toJson (this). – user802467

+0

@ user802467 intendi servizio Android? – Preetam

2

Questo errore è comune quando si dispone di un logger nella propria super classe.Come @Zar suggerito in precedenza, è possibile utilizzare statica per il vostro campo logger, ma questo funziona anche:

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

P.S. probabilmente funzionerà e con annotazione @Expose controllare di più su questo qui: https://stackoverflow.com/a/7811253/1766166

0

BomItem si riferisce a BOMModule (Collection<BomModule> modules), e si riferisce a BOMModuleBOMItem (Collection<BomItem> items). La libreria Gson non ama i riferimenti circolari. Rimuovi questa dipendenza circolare dalla tua classe. Anch'io ho dovuto affrontare lo stesso problema in passato con lib libiche.

7

Se si utilizza Realm e si ottiene questo errore e l'oggetto 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 sono perso a farlo per uno solo tra un mucchio di oggetti copiati ... ho impiegato anni per realizzare come la traccia dello stack non nomina la classe/tipo di oggetto. Il problema è che il problema è causato da un riferimento circolare, ma si tratta di un riferimento circolare da qualche parte nella classe base RealmObject, non nella propria sottoclasse, che rende più difficile da individuare!

+0

Questo è corretto!Nel mio caso cambia il mio elenco oggetti interrogato direttamente da realm a ArrayList copyList = new ArrayList <>(); per (Immagine: immagini) { copyList.add (realm.copyFromRealm (image)); } –

4

La mia risposta è un po 'in ritardo, ma penso che questa domanda non abbia ancora una buona soluzione. L'ho trovato in origine here.

Con GSON è possibile contrassegnare i campi che si fanno vogliono essere inclusi in JSON con @Expose e creare l'oggetto GSON con:

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

che ha fatto il trucco per me!

Problemi correlati