it-swarm.com.de

gson.toJson () wirft StackOverflowError aus

Ich möchte aus meinem Objekt einen JSON-String generieren:

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

Jedes Mal, wenn ich dies versuche, erhalte ich folgende Fehlermeldung:

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)

Dies sind die Attribute meiner BomItem Klasse:

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;

Attribute meiner referenzierten BomModule class:

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

Irgendeine Idee, was diesen Fehler verursacht? Wie kann ich es reparieren?

64
nimrod

Dieses Problem besteht darin, dass Sie eine Zirkelreferenz haben.

In der BomModule-Klasse verweisen Sie auf:

private Collection<BomModule> parentModules;
private Collection<BomModule> subModules;

Dieser Selbstbezug auf BomModule wurde von GSON offensichtlich nicht gemocht.

Eine Problemumgehung besteht einfach darin, die Module auf null zu setzen, um das rekursive Looping zu vermeiden. Auf diese Weise kann ich die StackOverFlow-Exception vermeiden.

item.setModules(null);

Oder markieren Sie die Felder, die Sie nicht möchten mit dem Schlüsselwort transient im serialisierten json anzeigen sollen, z.

private transient Collection<BomModule> parentModules;
private transient Collection<BomModule> subModules;
62
SLaks

Ich hatte dieses Problem, als ich einen Log4J-Logger als Klasseneigenschaft hatte, zum Beispiel:

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

Dies kann gelöst werden, indem Sie entweder den Logger static machen oder ihn einfach in die eigentlichen Funktionen verschieben.

24
Zar

Wenn Sie Realm verwenden und dieser Fehler angezeigt wird und das Objekt, das den Fehler verursacht, RealmObject erweitert, vergessen Sie nicht, realm.copyFromRealm(myObject) zu tun, um eine Kopie ohne alle Realm-Bindungen zu erstellen, bevor Sie zur Serialisierung an GSON gelangen.

Ich hatte dies nur für eine Gruppe von Objekten, die kopiert wurden, verpasst. Ich brauchte eine Ewigkeit, um zu erkennen, da die Stack-Ablaufverfolgung nicht die Objektklasse/-art benennt. Das Problem ist zwar auf einen Zirkelverweis zurückzuführen, aber es handelt sich um einen Zirkelverweis irgendwo in der RealmObject-Basisklasse, nicht um Ihre eigene Unterklasse.

15
Breeno

Wie SLaks sagte StackOverflowError, wenn in Ihrem Objekt ein Zirkelverweis vorhanden ist.

Um dies zu beheben, können Sie TypeAdapter für Ihr Objekt verwenden.

Wenn Sie beispielsweise nur String aus Ihrem Objekt generieren möchten, können Sie den Adapter folgendermaßen verwenden:

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

und registriere es so:

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

oder so, wenn Sie über eine Schnittstelle verfügen und einen Adapter für alle Unterklassen verwenden möchten:

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

Meine Antwort ist etwas spät, aber ich denke, diese Frage hat noch keine gute Lösung. Ich fand es ursprünglich hier .

Mit Gson können Sie die Felder markieren, die in json enthalten sein sollen , mit @Expose so was:

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

und erstelle das gson Objekt mit:

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

Zirkelverweise, die Sie gerade nicht aussetzen. Das hat den Trick für mich getan!

7
ffonz

Dieser Fehler tritt häufig auf, wenn Sie einen Logger in Ihrer Superklasse haben. Wie zuvor @Zar vorgeschlagen, können Sie static für Ihr Loggerfeld verwenden. Dies funktioniert jedoch auch:

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

P.S. Wahrscheinlich wird es funktionieren und mit @Expose Annotation können Sie hier mehr darüber erfahren: https://stackoverflow.com/a/7811253/1766166

2
zygimantus

Edit: Sorry für mein schlechtes, das ist meine erste Antwort. Danke für Ihre Ratschläge.

Ich erstelle meinen eigenen Json Converter

Die von mir verwendete Hauptlösung besteht darin, für jede Objektreferenz einen übergeordneten Objektsatz zu erstellen. Wenn eine Unterreferenz auf ein vorhandenes übergeordnetes Objekt verweist, wird es verworfen. Dann kombiniere ich mit einer zusätzlichen Lösung, indem ich die Referenzzeit einschränke, um Infinitivschleifen in bidirektionaler Beziehung zwischen Entitäten zu vermeiden.

Meine Beschreibung ist nicht so gut, hoffe es hilft euch Jungs.

Dies ist mein erster Beitrag zur Java-Community (Lösung Ihres Problems). Sie können es ausprobieren;) Es gibt eine README.md-Datei https://github.com/trannamtrung1st/TSON

1

Ich habe das gleiche Problem. In meinem Fall bestand der Grund darin, dass der Konstruktor meiner serialisierten Klasse die Kontextvariable wie folgt verwendet:

public MetaInfo(Context context)

Wenn ich dieses Argument lösche, ist der Fehler verschwunden.

public MetaInfo()
1
Denis

Vermeiden Sie unnötige Problemumgehungen, wie das Festlegen von Werten auf Null oder das Verändern von Feldern. Der richtige Weg, dies zu tun, besteht darin, eines der Felder mit @Expose zu kommentieren und Gson anzuweisen, nur die Felder mit der Anmerkung zu serialisieren:

private Collection<BomModule> parentModules;
@Expose
private Collection<BomModule> subModules;

...
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
0
Ismael Sarmento

Für Android-Benutzer können Sie eine Bundle nicht serialisieren, da eine Selbstreferenz auf Bundle eine StackOverflowError verursacht.

Um ein Bundle zu serialisieren, register eine BundleTypeAdapterFactory .

0
Cord Rehn

BomItem bezieht sich auf BOMModule (Collection<BomModule> modules) und BOMModule bezieht sich auf BOMItem (Collection<BomItem> items). Gson-Bibliothek mag keine Zirkelverweise. Entfernen Sie diese zirkulare Abhängigkeit von Ihrer Klasse. Auch ich hatte in der Vergangenheit mit gson lib dasselbe Problem.

0
Binita Bharati

Ich hatte ein ähnliches Problem, bei dem die Klasse eine InputStream-Variable hatte, die ich nicht unbedingt beibehalten musste. Daher wurde das Problem durch Ändern in "Transient" behoben.

0
Kamalakannan V

In Android erwies sich der Überlauf des Gson-Stacks als Deklaration eines Handlers. Es wurde in eine Klasse verschoben, die nicht deserialisiert wird.

Basierend auf Zars Empfehlung, habe ich den Handler statisch gemacht, als dies in einem anderen Codeabschnitt der Fall war. Die Statik des Handlers funktionierte ebenfalls.

0
Dan

Ich hatte dieses Problem für mich, wenn ich:

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

in meinem Objekt ... was nach etwa einer Stunde Debuggen vollkommen Sinn machte!

0
keesp