gson.toJson () স্ট্যাক ওভারফ্লো এরিয়ার ছুড়ে ফেলে


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)

এগুলি আমার বমআইটিম শ্রেণীর বৈশিষ্ট্যগুলি :

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;

আমার রেফারেন্সড বমমডুল ক্লাসের বৈশিষ্ট্য:

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স্পষ্টতই, জিএসওএন এটি পছন্দ করে নি সেই স্ব উল্লেখটি ।

একটি recarive nullলুপিং এড়ানোর জন্য একটি workaround সবেমাত্র মডিউল সেট করা হয়। এইভাবে আমি স্ট্যাকওভারফ্লো-ব্যতিক্রম এড়াতে পারি।

item.setModules(null);

অথবা কীওয়ার্ড ব্যবহার করে সিরিয়ালযুক্ত জসনটিতে আপনি যে ক্ষেত্রগুলি প্রদর্শন করতে চান না তা চিহ্নিত করুন transient: উদাহরণস্বরূপ:

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

হ্যাঁ একটি বমমডুল অবজেক্ট অন্য BomModule অবজেক্টের অংশ হতে পারে।
নিম্রোদ

তবে কি সমস্যা? 'সংগ্রহ <বমমডিউল> মডিউলগুলি' কেবল একটি সংগ্রহ, এবং আমি মনে করি যে জিএসন এটির থেকে একটি সাধারণ অ্যারে তৈরি করতে সক্ষম হবে?
নিম্রোদ

@ ডুনোট: সংগ্রহের কোনও বস্তু কি তাদের পিতামাতাকে বোঝায়?
স্ল্যাक्स

আমি আপনাকে ঠিক পেয়েছি কিনা তা নিশ্চিত নই, তবে হ্যাঁ। উপরের আপডেট হওয়া প্রশ্নটি দয়া করে দেখুন।
নিম্রোদ

@ ডুনোট: আমার সন্দেহ হিসাবে, পিতামাতা ও শিশু সংগ্রহগুলি সিরিয়ালকরণ করার সময় এটি একটি অসীম লুপে যায়। আপনি কী ধরনের জেএসএন এটি লেখার প্রত্যাশা করছেন?
স্ল্যাक्स

30

আমার যখন ক্লাস সম্পত্তি হিসাবে লগ 4 জে লগার ছিল তখন আমার এই সমস্যা হয়েছিল:

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

এটি লগার তৈরি করে staticবা কেবল আসল ফাংশন (গুলি) এ সরানোর মাধ্যমে সমাধান করা যেতে পারে ।


4
একেবারে দুর্দান্ত ক্যাচ। ক্লাসের সেই স্ব-রেফারেন্স অবশ্যই GSON পছন্দ করেন না। আমাকে অনেক মাথাব্যথা বাঁচিয়েছে! +1
খ্রিস্টোফার

4
এটির সমাধানের আরেকটি উপায় হ'ল ক্ষেত্রের মধ্যে ক্ষণস্থায়ী পরিবর্তনকারী
gawi

লগার বেশিরভাগ স্থির হওয়া উচিত। অন্যথায় আপনি প্রতিটি অবজেক্ট তৈরির জন্য সেই লগার উদাহরণ পাওয়ার জন্য ব্যয় করতে হবে, যা সম্ভবত আপনি চান না। (
ব্যয়টি

26

যদি আপনি রিয়েলম ব্যবহার করে থাকেন এবং আপনি এই ত্রুটিটি পেয়ে থাকেন এবং সমস্যাটি দেওয়ার বিষয়টি রিয়েলমবজেক্টকে প্রসারিত করে, realm.copyFromRealm(myObject)সিরিয়ালাইজেশনের জন্য জিএসএন-এ যাওয়ার আগে সমস্ত রিয়েল বাইন্ডিং ছাড়াই একটি অনুলিপি তৈরি করতে ভুলবেন না ।

আমি একগুচ্ছ অবজেক্টের অনুলিপি করার জন্য কেবল এটির জন্য মিস করেছি ... স্ট্যাক ট্রেসটি অবজেক্ট ক্লাস / টাইপের নাম না রাখায় আমাকে বুঝতে পেরে যুগে যুগে সময় লেগেছিল। বিষয়টি হ'ল, সমস্যাটি একটি বিজ্ঞপ্তিগত রেফারেন্সের কারণে হয়েছিল তবে এটি রিয়েলমজেক্ট বেস ক্লাসের কোথাও একটি বিজ্ঞপ্তিযুক্ত রেফারেন্স, আপনার নিজের সাবক্লাস নয়, যা এটি খুঁজে পাওয়া শক্ত করে!


4
এটাই সঠিক! আমার ক্ষেত্রে আমার অবজেক্টের তালিকাটি রাজ্য থেকে সরাসরি অ্যারেলিস্টে অনুসন্ধান করা হয়েছে <চিত্র> কপিলিস্ট = নতুন অ্যারেলিস্ট <> (); (চিত্র চিত্র: চিত্র) এর জন্য {copyList.add (realm.copyFromRealm (চিত্র)); }
রিকার্ডো মুট্টি

রাজ্য ব্যবহার করে, সমস্যাটি সমাধান করার জন্য এটিই সমাধান ছিল, ধন্যবাদ
জুড ফার্নান্দিস

13

যেমন স্ল্যাকস বলেছে স্ট্যাক ওভারফ্লো এরর যদি আপনার অবজেক্টে বিজ্ঞপ্তি থাকে তবে ঘটবে।

এটি ঠিক করার জন্য আপনি আপনার অবজেক্টের জন্য টাইপএডাপ্টার ব্যবহার করতে পারেন।

উদাহরণস্বরূপ, আপনার যদি প্রয়োজন হয় কেবল আপনার অবজেক্ট থেকে স্ট্রিং উত্পন্ন করার জন্য আপনি এই জাতীয় অ্যাডাপ্টার ব্যবহার করতে পারেন:

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

আমার উত্তরটি কিছুটা দেরিতে হলেও আমার মনে হয় এই প্রশ্নের এখনও কোনও ভাল সমাধান নেই। আমি এটি মূলত এখানে পেয়েছি ।

জিসনের সাহায্যে আপনি যে ক্ষেত্রগুলিকে জেসসনে অন্তর্ভুক্ত করতে চান তা চিহ্নিত করতে পারেন @Expose:

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

এবং এর সাথে জিএসএন অবজেক্ট তৈরি করুন:

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

বিজ্ঞপ্তি উল্লেখ আপনি প্রকাশ করা হবে না । এটা আমার জন্য কৌতুক!


আপনি কি জানেন যে কোনও টীকা আছে যা এর বিপরীত করে? এখানে 4 টি ক্ষেত্র রয়েছে যা আমি উপেক্ষা করতে হবে এবং 30 টিরও বেশি আমাকে অন্তর্ভুক্ত করতে হবে।
jDub9

@ jDub9 আমার দেরী উত্তরটির জন্য দুঃখিত, তবে আমি ছুটিতে রয়েছি। কটাক্ষপাত আছে এই উত্তর। আশা করি এটি আপনার সমস্যার সমাধান করে
ffonz

3

আপনার সুপার ক্লাসে লগার থাকলে এই ত্রুটিটি সাধারণ is @ জার আগে যেমন প্রস্তাব করেছিলেন, আপনি আপনার লগার ক্ষেত্রের জন্য স্ট্যাটিক ব্যবহার করতে পারেন , তবে এটি কাজ করে:

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

পিএস সম্ভবত এটি কাজ করবে এবং @ এক্সপোজ টীকা সহ এ সম্পর্কে এখানে আরও চেক করুন: https://stackoverflow.com/a/7811253/1766166


1

আমি একই সমস্যা আছে। আমার ক্ষেত্রে কারণটি ছিল যে আমার সিরিয়ালাইজড ক্লাসের নির্মাতা প্রসঙ্গে ভেরিয়েবলটি গ্রহণ করেন:

public MetaInfo(Context context)

আমি যখন এই যুক্তিটি মুছব তখন ত্রুটি চলে গেছে।

public MetaInfo()

4
প্রসঙ্গ হিসাবে পরিষেবা অবজেক্ট রেফারেন্স পাস করার সময় আমি এই সমস্যার মুখোমুখি হয়েছি। ফিক্সটি ছিল শ্রেণিতে প্রাসঙ্গিক পরিবর্তনশীল স্থিতিশীল করা যা gson.toJson (এটি) ব্যবহার করে।
ব্যবহারকারী 802467

@ ব্যবহারকারী 802467 আপনি কি অ্যান্ড্রয়েড পরিষেবা বোঝাতে চান?
প্রীতম

1

সম্পাদনা: আমার খারাপের জন্য দুঃখিত, এটি আমার প্রথম উত্তর। আপনার পরামর্শের জন্য ধন্যবাদ।

আমি আমার নিজস্ব জসন কনভার্টার তৈরি করি

আমি যে প্রধান সমাধানটি ব্যবহার করেছি তা হ'ল প্রতিটি বস্তুর রেফারেন্সের জন্য পিতামাতার অবজেক্ট সেট তৈরি করা। যদি একটি সাব-রেফারেন্স বিদ্যমান প্যারেন্ট অবজেক্টের দিকে নির্দেশ করে তবে তা বাতিল করে দেবে। তারপরে সত্ত্বার মধ্যে দ্বি-দিকনির্দেশক সম্পর্কের অনন্য লুপ এড়াতে আমি রেফারেন্স সময়কে সীমাবদ্ধ করে একটি অতিরিক্ত সমাধানের সাথে একত্রিত করি।

আমার বিবরণটি খুব ভাল নয়, আশা করি এটি আপনাকে সাহায্য করবে helps

এটি জাভা সম্প্রদায়ে আমার প্রথম অবদান (আপনার সমস্যার সমাধান)। আপনি এটি পরীক্ষা করে দেখতে পারেন;) এখানে একটি README.md ফাইল রয়েছে https://github.com/trannamtrung1st/TSON


4
একটি সমাধানের একটি লিঙ্ক স্বাগত, তবে দয়া করে আপনার উত্তরটি কার্যকর না হওয়া নিশ্চিত করুন: লিঙ্কটির চারপাশে প্রসঙ্গ যুক্ত করুন যাতে আপনার সহ ব্যবহারকারীদের কিছু ধারণা থাকতে পারে এটি কী এবং কেন এটি রয়েছে, তারপরে আপনি পৃষ্ঠার সর্বাধিক প্রাসঙ্গিক অংশটি উদ্ধৃত করুন লক্ষ্য পৃষ্ঠাটি অনুপলব্ধ ক্ষেত্রে লিঙ্কটি পুনরায় সংযুক্ত করুন। লিঙ্কের চেয়ে সামান্য বেশি উত্তর মুছতে পারে।
পল রাউব

4
স্ব-প্রচার কেবল নিজের লাইব্রেরি বা টিউটোরিয়ালের সাথে লিঙ্ক করা ভাল উত্তর নয়। এটির সাথে লিঙ্ক করা, কেন এটি সমস্যার সমাধান করে তা ব্যাখ্যা করে, কীভাবে এটি করা যায় তার কোড সরবরাহ করা এবং আপনি যে এটি লিখেছিলেন তা অস্বীকার করা আরও ভাল উত্তরের জবাব দেয়। দেখুন: "ভাল" স্ব প্রচারের অর্থ কী?
শ্রী

অনেক ধন্যবাদ. আমি আমার উত্তর সম্পাদনা করেছি। আশা করি এটি ভাল হয়ে যাবে: ডি
ট্রেন নাম ট্রুং

অন্যান্য মন্তব্যকারীরা যা বলেছিলেন তার অনুরূপ, আপনার পোস্টে আপনার কোডের সর্বাধিক গুরুত্বপূর্ণ অংশগুলি প্রদর্শন করা পছন্দীয়। এছাড়াও, আপনার উত্তরের ভুলগুলির জন্য আপনাকে ক্ষমা চাইতে হবে না।
0x কার্সার

0

অ্যান্ড্রয়েডে, জিএসএন স্ট্যাক ওভারফ্লো হ্যান্ডলারের ঘোষণার হিসাবে পরিণত হয়েছিল। এটিকে এমন এক শ্রেণিতে স্থানান্তরিত করেছেন যা deserialized করা হচ্ছে না।

জারের সুপারিশের ভিত্তিতে, কোডের অন্য বিভাগে যখন ঘটেছিল তখন আমি হ্যান্ডলারটিকে স্থির করে তুলি। হ্যান্ডলার স্থির করে তোলে পাশাপাশি কাজ করে।


0

BomItemবোঝায় BOMModule( Collection<BomModule> modules), এবং BOMModuleবোঝায় BOMItem( Collection<BomItem> items)। জসন লাইব্রেরি বিজ্ঞপ্তি সংক্রান্ত রেফারেন্স পছন্দ করে না। আপনার ক্লাস থেকে এই বিজ্ঞপ্তি নির্ভরতা অপসারণ। আমিও অতীতে জিএসএন লাইব নিয়ে একই সমস্যার মুখোমুখি হয়েছিলাম।


0

আমি যখন রাখি তখন আমার এই সমস্যাটি ঘটেছিল:

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

আমার অবজেক্টে ... যা ডিবাগ করার এক ঘন্টা বা তার পরে নিখুঁত ধারণা তৈরি করেছে!


0

অ্যান্ড্রয়েড ব্যবহারকারীদের জন্য, আপনি একটি ধারাবাহিকভাবে করতে পারবে না Bundleএকটি স্ব-ক্ষমতাযুক্ত উল্লেখের করণে Bundleএকটি ঘটাচ্ছে StackOverflowError

একটি বান্ডিল সিরিয়ালাইজ করতে, একটিBundleTypeAdapterFactory


0

অপ্রয়োজনীয় কাজের ক্ষেত্রগুলি এড়িয়ে চলুন, যেমন মানগুলি স্থির করে দেওয়া বা ক্ষেত্রগুলিকে ক্ষণস্থায়ী করা making এটি করার সঠিক উপায়টি হ'ল @ এক্সপোজ সহ কোনও একটি ক্ষেত্রকে টীকায়িত করা এবং তারপরে জিসনকে টীকাগুলির সাথে কেবল ক্ষেত্রগুলি সিরিয়াল করতে বলা:

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করতে পারেFooOneToMany আবার ট্রিগার করতে পারে ...

উত্তরটি ব্যক্তিগত অভিজ্ঞতার ভিত্তিতে তৈরি হয়, অতএব বিনা দ্বিধায় মন্তব্য করতে, আমাকে ভুল প্রমাণ করতে, ভুল সংশোধন করতে, বা উত্তর প্রসারিত করতে নির্দ্বিধায়। যাইহোক আমি আশা করি যে কেউ এই উত্তরটি দরকারী বলে মনে করবে।


হ্যান্ডেল সিরিয়ালাইজেশন প্রোখেসের জন্য অ্যাডাপ্টারের সংজ্ঞা দেওয়া সাইক্লিক নির্ভরতা হ্যান্ডেল করার অন্য উপায়। আপনার কাছে বিকল্প রয়েছে যদিও অন্যান্য টীকাগুলি রয়েছে যা অ্যাডাপ্টারগুলি লেখার পরিবর্তে এটি ঘটতে বাধা দিতে পারে।
সারিক শায়খ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.