2012-04-18 2 views
50

Я хотел бы генерировать JSON строки из моего объекта:gson.toJson() бросает StackOverflowError

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

Everytime я пытаюсь сделать это, я получаю эту ошибку:

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; 

атрибуты моего справочника CED 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; 

Любая идея, что вызывает эту ошибку? Как я могу это исправить?

+0

Может случиться, что вы помещаете экземпляр объекта внутри себя где-то внутри gson. –

+0

Исключение теряет основную причину, когда запускает журнал с помощью 'JsonWriter.java:473)', как определить основную причину переполнения контейнера Gson – Siddharth

ответ

52

Возможно, это произойдет, если у вас есть круговая ссылка.

Содержит ли BomModule ваш родительский объект?

+0

Да, объект BomModule может быть частью другого объекта BomModule. – doonot

+0

Но это проблема? 'Collection modules' - это только коллекция, и я думаю, что gson должен быть в состоянии сделать простой массив из этого? – doonot

+0

@dooonot: Может ли какой-либо из объектов в коллекции ссылаться на их родительский объект? – SLaks

21

У меня была эта проблема, когда я был регистратор Log4J как свойство класса, такие как:

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

Это может быть решена либо делает регистратор static или просто перемещая его в реальной функции (ий).

+4

Абсолютно замечательный улов. Эта самооценка класса, явно не понравившегося GSON, спасла меня от многих головных болей !+1 – christopher

+1

другой способ решить эту проблему, добавив переходный модификатор в поле – gawi

+0

. Регистратор должен быть в основном статическим. В противном случае вы понесете затраты на получение экземпляра Logger для каждого создания объекта, что, вероятно, не то, что вы хотите. (Стоимость не является тривиальной) – stolsvik

0

В Android переполнение стека gson оказалось объявлением обработчика. Переместил его в класс, который не десериализуется.

Основываясь на рекомендации Zar, я поставил обработчик статическим, когда это произошло в другом разделе кода. Также работала старая обработчик.

10

Как сказал Слэкс, StackOverflowError произойдет, если у вас есть круговая ссылка в вашем объекте.

Чтобы исправить это, вы можете использовать TypeAdapter для своего объекта.

Например, если вам нужно только сформировать строку из вашего объекта, вы можете использовать адаптер, как это:

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

У меня такая же проблема. В моем случае причина в том, что конструктор моего сериализованного переменного контекста класс принимает, например:

public MetaInfo(Context context) 

Когда я удалить этот аргумент, пошла ошибка.

public MetaInfo() 
+1

Я столкнулся с этой проблемой при передаче ссылки на объект службы в качестве контекста. Исправлено было сделать переменную context static в классе, который использует gson.toJson (this). – user802467

+0

@ пользователь802467 вы имеете в виду андроид сервис? – Preetam

2

Эта ошибка распространена, когда у вас есть регистратор в вашем суперклассе.Как @Zar предложено ранее, вы можете использовать статический для поля регистратора, но это также работает:

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

P.S. вероятно, он будет работать и с @Expose аннотации проверить больше об этом здесь: https://stackoverflow.com/a/7811253/1766166

0

BomItem относится к BOMModule (Collection<BomModule> modules) и BOMModule относится к BOMItem (Collection<BomItem> items). Библиотека Gson не любит круговые ссылки. Удалите эту циклическую зависимость от вашего класса. В прошлом я тоже сталкивался с такой же проблемой с gson lib.

7

Если вы используете Realm, и вы получите эту ошибку, и объект, вызывающий проблемы, расширяет RealmObject, не забудьте сделать realm.copyFromRealm(myObject), чтобы создать копию без привязки Realm до перехода на GSON для сериализации.

Я пропустил это только для одного из множества копируемых объектов ... взял меня на себя, чтобы понять, как трассировка стека не называет класс/тип объекта. Дело в том, что проблема вызвана круговой ссылкой, но это круговая ссылка где-то в базовом классе RealmObject, а не на ваш собственный подкласс, что затрудняет ее обнаружение!

+0

Это правильно! В моем случае измените список объектов, запрошенных напрямую из области в ArrayList copyList = new ArrayList <>(); для (Изображение изображения: изображения) { copyList.add (realm.copyFromRealm (изображение)); } –

4

Мой ответ немного запоздал, но я думаю, что у этого вопроса пока нет хорошего решения. Я нашел это изначально here.

С Gson Вы можете отметить поля, которые вы сделать хотите быть включены в JSON с @Expose и создать объект gson с:

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

Это сделал трюк для меня!