gson.toJson () StackOverflowError को फेंकता है


87

मैं अपनी वस्तु से JSON स्ट्रिंग उत्पन्न करना चाहूंगा:

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

जब भी मैं ऐसा करने की कोशिश करता हूं, मुझे यह त्रुटि मिलती है:

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)

ये मेरे BomItem वर्ग की विशेषताएं हैं :

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;

मेरे संदर्भित BomModule वर्ग के गुण :

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

किसी भी विचार क्या इस त्रुटि का कारण बनता है? मेरे द्वारा यह कैसे किया जा सकता है?


अगर आप किसी वस्तु को उदाहरण के रूप में कहीं अंदर रख सकते हैं, तो ऐसा हो सकता है।
क्रिस्टोफ रूसो

अपवाद मूल कारण को खो देता है एक लॉग के साथ शुरू होता है JsonWriter.java:473), कैसे गन्स स्टैकओवरफ़्लो के मूल कारण की पहचान करता है
सिद्धार्थ

जवाबों:


86

वह समस्या यह है कि आपके पास एक परिपत्र संदर्भ है।

में BomModuleवर्ग आप को संदर्भित कर रहे हैं:

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

यही कारण है कि स्वयं संदर्भ के लिए BomModule, स्पष्ट रूप से, सभी एक ही GSON द्वारा पसंद नहीं।

nullपुनरावर्ती लूपिंग से बचने के लिए वर्कअराउंड सिर्फ मॉड्यूल सेट किया जाता है। इस तरह मैं StackOverFlow-Exception से बच सकता हूँ।

item.setModules(null);

या उन फ़ील्ड्स को चिह्नित करें जिन्हें आप कीवर्ड का उपयोग करके क्रमबद्ध json में दिखाना नहीं चाहते हैंtransient , जैसे:

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

हाँ एक BomModule ऑब्जेक्ट किसी अन्य BomModule ऑब्जेक्ट का हिस्सा हो सकता है।
निमरोड

लेकिन क्या यह एक समस्या है? 'संग्रह <BomModule> मॉड्यूल' केवल एक संग्रह है, और मुझे लगता है कि गेसन को इसमें से एक सरल सरणी बनाने में सक्षम होना चाहिए?
निमरोड़

@dooonot: क्या संग्रह की कोई भी वस्तु उनकी मूल वस्तु को संदर्भित करती है?
SLACs

मुझे यकीन नहीं है कि मैं तुम्हें सही मिला, लेकिन हाँ। कृपया अद्यतन प्रश्न ऊपर देखें।
निमरोड़

@dooonot: जैसा कि मुझे संदेह था, माता-पिता और बच्चे के संग्रह को क्रमबद्ध करते समय यह एक अनंत लूप में चला जाता है। आप इसे लिखने के लिए JSON से किस तरह की उम्मीद करते हैं?
SLACs

30

जब मुझे एक वर्ग की संपत्ति के रूप में एक Log4J लकड़हारा था, तो मुझे यह समस्या थी:

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

इसे लकड़हारा बनाकर staticया इसे वास्तविक कार्य में बदलकर हल किया जा सकता है ।


4
एकदम शानदार कैच। कक्षा के लिए यह आत्म संदर्भ स्पष्ट रूप से GSON को बिल्कुल पसंद नहीं है। मुझे बहुत सिरदर्द से बचाया! +1
क्रिस्टोफर

1
इसे हल करने का एक और तरीका है, क्षेत्र के लिए क्षणिक संशोधक जोड़कर
16

लकड़हारा ज्यादातर स्थिर होना चाहिए। अन्यथा आप प्रत्येक वस्तु के निर्माण के लिए उस लकड़हारे उदाहरण को प्राप्त करने की लागत को मान लेंगे, जो कि शायद आप नहीं चाहते हैं। (लागत तुच्छ नहीं है)
stolsvik

26

यदि आप Realm का उपयोग कर रहे हैं और आपको यह त्रुटि मिलती है, और परेशानी देने वाली वस्तु RealmObject का विस्तार करती है, तो realm.copyFromRealm(myObject)क्रमांकन के लिए GSON से गुजरने से पहले सभी Realm बाइंडिंग के बिना एक प्रतिलिपि बनाने के लिए मत भूलना ।

मैं कॉपी किए जा रहे वस्तुओं के एक समूह के बीच ऐसा करने से चूक गया ... मुझे एहसास हुआ कि स्टैक ट्रेस ऑब्जेक्ट क्लास / प्रकार का नाम नहीं है। बात यह है कि, यह मुद्दा एक परिपत्र संदर्भ के कारण होता है, लेकिन यह RealmObject बेस क्लास में कहीं न कहीं एक परिपत्र संदर्भ है, न कि आपका अपना उपवर्ग, जो इसे स्पॉट करना कठिन बनाता है!


1
यह सही है! मेरे मामले में मेरी वस्तु सूची को वास्तविक से सीधे ArrayList <image> copyList = new ArrayList <> () में बदल दिया; के लिए (छवि छवि: चित्र) {copyList.add (realm.copyFromRealm (छवि)); }
रिकार्डो मठ

दायरे का उपयोग करना, यह वास्तव में समाधान था जो समस्या को हल करता है, धन्यवाद
जूड फर्नांडिस

13

जैसा कि SLaks ने कहा कि StackOverflowError तब होता है जब आपके पास अपनी वस्तु में परिपत्र संदर्भ होता है।

इसे ठीक करने के लिए आप अपने ऑब्जेक्ट के लिए टाइप एडेप्टर का उपयोग कर सकते हैं।

उदाहरण के लिए, यदि आपको अपनी वस्तु से केवल स्ट्रिंग उत्पन्न करने की आवश्यकता है, तो आप इस तरह से एडाप्टर का उपयोग कर सकते हैं:

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

और इसे इस तरह पंजीकृत करें:

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

या इस तरह, यदि आपके पास इंटरफ़ेस है और इसके सभी उपवर्गों के लिए एडेप्टर का उपयोग करना चाहते हैं:

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

9

मेरा जवाब थोड़ा देर से है, लेकिन मुझे लगता है कि इस प्रश्न का अभी तक कोई अच्छा समाधान नहीं है। मैंने इसे मूल रूप से यहां पाया ।

Gson के साथ आप उन क्षेत्रों को चिह्नित कर सकते हैं जिन्हें आप इस तरह से json में शामिल करना चाहते हैं @Expose:

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

और gson ऑब्जेक्ट को इसके साथ बनाएँ:

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

परिपत्र संदर्भ जो आप अभी उजागर नहीं करते हैं। मेरे लिए यही चाल चली!


क्या आप जानते हैं कि क्या कोई एनोटेशन है जो इसके विपरीत करता है? ऐसे 4 क्षेत्र हैं जिन्हें मुझे अनदेखा करने की आवश्यकता है और 30 से अधिक को शामिल करने की आवश्यकता है।
jDub9

@ jDub9 मेरे देर से जवाब के लिए क्षमा करें, लेकिन मैं छुट्टी पर रहा हूं। इस जवाब पर एक नजर । आशा है कि यह आपकी समस्या को हल करता है
ffonz

3

जब आप अपने सुपर क्लास में लकड़हारा हो तो यह त्रुटि आम है। जैसा कि @Zar ने पहले सुझाव दिया था, आप अपने लकड़हारे क्षेत्र के लिए स्थैतिक का उपयोग कर सकते हैं , लेकिन यह भी काम करता है:

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

पुनश्च शायद यह काम करेगा और @ एनाउंसमेंट एनोटेशन के साथ इस बारे में अधिक जानकारी यहां देखें: https://stackoverflow.com/a/7811253/1766166


1

मेरी भी यही समस्या है। मेरे मामले में कारण यह था कि मेरे क्रमबद्ध वर्ग के निर्माता संदर्भ चर लेते हैं, जैसे:

public MetaInfo(Context context)

जब मैं इस तर्क को हटाता हूं, तो त्रुटि हो गई है।

public MetaInfo()

1
सेवा ऑब्जेक्ट संदर्भ को संदर्भ के रूप में पास करते समय मुझे इस समस्या का सामना करना पड़ा। फिक्स वर्ग में संदर्भ चर को स्थिर बनाने के लिए था जो gson.toJson (यह) का उपयोग करता है।
user802467

@ user802467 क्या आपका मतलब Android सेवा है?
प्रीतम

1

संपादित करें: मेरे बुरे के लिए क्षमा करें, यह मेरा पहला उत्तर है। आपकी सलाह के लिए धन्यवाद।

मैं अपना स्वयं का Json परिवर्तक बनाता हूँ

मेरे द्वारा उपयोग किया जाने वाला मुख्य समाधान प्रत्येक ऑब्जेक्ट संदर्भ के लिए माता-पिता ऑब्जेक्ट सेट करना है। यदि कोई उप-संदर्भ मौजूद पैरेंट ऑब्जेक्ट को इंगित करता है, तो यह त्याग देगा। फिर मैं एक अतिरिक्त समाधान के साथ गठबंधन करता हूं, संस्थाओं के बीच द्वि-दिशात्मक संबंधों में असीम पाश से बचने के लिए संदर्भ समय को सीमित करता हूं।

मेरा वर्णन बहुत अच्छा नहीं है, आशा है कि यह आप लोगों की मदद करेगा।

जावा समुदाय में यह मेरा पहला योगदान है (आपकी समस्या का समाधान)। आप इसे देख सकते हैं;) एक README.md फ़ाइल है https://github.com/trannamtrung1st/TSON


2
किसी समाधान के लिए लिंक का स्वागत है, लेकिन कृपया सुनिश्चित करें कि आपका उत्तर इसके बिना उपयोगी है: लिंक के चारों ओर संदर्भ जोड़ें ताकि आपके साथी उपयोगकर्ताओं को कुछ पता चले कि यह क्या है और यह क्यों है, तो पृष्ठ के सबसे प्रासंगिक हिस्से को उद्धृत करें ' मामले में लक्ष्य पृष्ठ अनुपलब्ध होने पर पुनः लिंक करना। ऐसे लिंक जो किसी लिंक से बहुत कम हैं उन्हें हटाया जा सकता है।
पॉल रौब

2
सेल्फ प्रमोशन बस अपने स्वयं के पुस्तकालय या ट्यूटोरियल से जोड़ना एक अच्छा जवाब नहीं है। इसे लिंक करना, यह बताना कि यह समस्या क्यों हल करता है, ऐसा करने के लिए कोड प्रदान करना और यह बताना कि आपने इसे बेहतर उत्तर के लिए बनाया है। देखें: क्या "अच्छा" आत्म प्रचार दर्शाता है?
श्री

बहुत बहुत धन्यवाद। मैंने अपना उत्तर संपादित कर लिया था। आशा है कि यह ठीक होगा: D
Trần Nam Trung

अन्य टिप्पणीकारों ने जो कहा, उसके समान यह पसंद किया जाता है कि आप अपनी पोस्ट में अपने कोड के सबसे महत्वपूर्ण भागों को दिखाएं। इसके अलावा, आपको अपने उत्तर में गलतियों के लिए माफी माँगने की आवश्यकता नहीं है।
0xCursor

0

एंड्रॉइड में, गन्स स्टैक ओवरफ्लो एक हैंडलर की घोषणा के रूप में निकला। इसे एक ऐसे वर्ग में स्थानांतरित कर दिया गया है, जहां इसका निरसन नहीं किया जा रहा है।

ज़ार की सिफारिश के आधार पर, मैंने हैंडलर को तब स्थिर बना दिया जब कोड के किसी अन्य अनुभाग में ऐसा हुआ। हैंडलर को स्थिर बनाने के साथ ही काम किया।


0

BomItemसंदर्भित करता है BOMModule( Collection<BomModule> modules), और BOMModuleसंदर्भित करता है BOMItem( Collection<BomItem> items)। Gson पुस्तकालय परिपत्र संदर्भ पसंद नहीं करता है। अपनी कक्षा से इस परिपत्र निर्भरता को निकालें। मैं भी पहले से ही समस्या का सामना करना पड़ा gson lib के साथ।


0

मेरे सामने यह समस्या आई जब मैंने डाला:

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

मेरी वस्तु में ... जो एक घंटे या डिबगिंग के बाद एकदम सही समझ में आया!



0

अनावश्यक वर्कअराउंड से बचें, जैसे मान को शून्य या फ़ील्ड को क्षणिक बनाने के लिए। ऐसा करने का सही तरीका है, @Expose वाले किसी एक फ़ील्ड को एनोटेट करना और फिर Gson को केवल एनोटेशन वाले फ़ील्ड को क्रमबद्ध करना बताएं:

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

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

0

मेरे पास एक समान मुद्दा था जहां कक्षा में एक इनपुटस्ट्रीम चर था जो मुझे वास्तव में जारी रखने के लिए नहीं था। इसलिए इसे क्षणिक में बदलने से समस्या हल हो गई।


0

कुछ समय इस मुद्दे से लड़ने के बाद, मेरा मानना ​​है कि मेरे पास एक समाधान है। समस्या अनसुलझे द्विदिश कनेक्शनों में है, और जब वे क्रमबद्ध किए जा रहे हैं तो कनेक्शन का प्रतिनिधित्व कैसे करें। उस व्यवहार को ठीक करने का तरीका gsonवस्तुओं को अनुक्रमित करने के तरीके को "बताना" है । उस उद्देश्य के लिए हम उपयोग करते हैं Adapters

उपयोग करके Adaptersहम बता सकते हैं gsonकि अपनी संपत्ति के Entityसाथ-साथ किस गुण को क्रमबद्ध करना है।

चलो Fooऔर Barदो संस्थाओं जहां होना Fooहै OneToManyके संबंध Barऔर Barहै ManyToOneके संबंध Foo। हम Barएडेप्टर को परिभाषित करते हैं जब gsonक्रमबद्ध करता है Bar, तो यह परिभाषित करके कि चक्रीय संदर्भ के Fooपरिप्रेक्ष्य से Barअनुक्रमित करना कैसे संभव नहीं होगा।

public class BarAdapter implements JsonSerializer<Bar> {
    @Override
    public JsonElement serialize(Bar bar, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("id", bar.getId());
        jsonObject.addProperty("name", bar.getName());
        jsonObject.addProperty("foo_id", bar.getFoo().getId());
        return jsonObject;
    }
}

यहां इकाई foo_idका प्रतिनिधित्व करने के लिए उपयोग किया जाता है Fooजिसे क्रमबद्ध किया जाएगा और जिसके कारण हमारी चक्रीय संदर्भ समस्या होगी। अब जब हम एडॉप्टर Fooका उपयोग करते हैं तो इसे फिर से क्रमबद्ध नहीं किया जाएगा Barकेवल इसकी आईडी ली जाएगी और इसमें डाल दिया जाएगा JSON। अब हमारे पास Barएडॉप्टर है और हम इसका उपयोग सीरीज़ करने के लिए कर सकते हैं Foo। यहाँ विचार है:

public String getSomething() {
    //getRelevantFoos() is some method that fetches foos from database, and puts them in list
    List<Foo> fooList = getRelevantFoos();

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Bar.class, new BarAdapter());
    Gson gson = gsonBuilder.create();

    String jsonResponse = gson.toJson(fooList);
    return jsonResponse;
}

स्पष्ट करने के लिए एक और बात, foo_idअनिवार्य नहीं है और इसे छोड़ दिया जा सकता है। इस उदाहरण में अनुकूलक का उद्देश्य क्रमानुसार करने है Barऔर रख कर foo_idहम चाहते हैं कि पता चला Barसकते हैं ट्रिगर ManyToOneपैदा करने के बिना Fooगति प्रदान करने के OneToManyलिए फिर से ...

उत्तर व्यक्तिगत अनुभव पर आधारित है, इसलिए मुझे गलत साबित करने, गलतियों को ठीक करने या उत्तर का विस्तार करने के लिए टिप्पणी करने के लिए स्वतंत्र महसूस करें। किसी भी तरह मुझे आशा है कि किसी को यह उत्तर उपयोगी लगेगा।


सीरियलाइजेशन के लिए एडेप्टर को परिभाषित करना प्रेकस खुद चक्रीय निर्भरता को संभालने का एक और तरीका है। आपके पास इसके लिए विकल्प है हालांकि अन्य एनोटेशन हैं जो एडेप्टर लिखने के बजाय ऐसा होने से रोक सकते हैं।
सरिक शेख
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.