Я хотел бы сгенерировать строку 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)
, как определить основную причину Gson stackoverflowОтветы:
Проблема в том, что у вас есть круговая ссылка.
В
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;
источник
У меня была эта проблема, когда у меня был логгер Log4J в качестве свойства класса, например:
private Logger logger = Logger.getLogger(Foo.class);
Это можно решить, сделав регистратор
static
или просто переместив его в фактическую функцию (ы).источник
Если вы используете Realm и получаете эту ошибку, а объект, вызывающий проблему, расширяет RealmObject, не забудьте
realm.copyFromRealm(myObject)
создать копию без всех привязок Realm, прежде чем перейти к GSON для сериализации.Я пропустил это только для одного из множества копируемых объектов ... мне потребовалось много времени, чтобы понять, поскольку трассировка стека не называет класс / тип объекта. Дело в том, что проблема вызвана циклической ссылкой, но это циклическая ссылка где-то в базовом классе RealmObject, а не в вашем собственном подклассе, что затрудняет обнаружение!
источник
Как сказал SLaks, StackOverflowError возникает, если у вас есть круговая ссылка в вашем объекте.
Чтобы исправить это, вы можете использовать TypeAdapter для своего объекта.
Например, если вам нужно только сгенерировать String из вашего объекта, вы можете использовать адаптер следующим образом:
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();
источник
Мой ответ немного запоздал, но я думаю, что у этого вопроса пока нет хорошего решения. Я нашел это изначально здесь .
С Gson вы можете отметить поля , которые вы действительно хотите быть включены в JSON с
@Expose
так:@Expose String myString; // will be serialized as myString
и создайте объект gson с помощью:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Циркулярные ссылки вы просто не выставляете. Это помогло мне!
источник
Эта ошибка часто встречается, когда у вас есть регистратор в вашем суперклассе. Как ранее предлагал @Zar, вы можете использовать static для поля своего регистратора, но это также работает:
protected final transient Logger logger = Logger.getLogger(this.getClass());
PS, вероятно, это сработает, и с аннотацией @Expose проверьте больше об этом здесь: https://stackoverflow.com/a/7811253/1766166
источник
У меня такая же проблема. В моем случае причина заключалась в том, что конструктор моего сериализованного класса принимает переменную контекста, например:
public MetaInfo(Context context)
Когда я удаляю этот аргумент, ошибка исчезла.
public MetaInfo()
источник
Изменить: извините за мою ошибку, это мой первый ответ. Спасибо за советы.
Я создаю свой собственный конвертер Json
Основное решение, которое я использовал, - создать набор родительских объектов для каждой ссылки на объект. Если вспомогательная ссылка указывает на существующий родительский объект, она будет отброшена. Затем я комбинирую с дополнительным решением, ограничивая время обращения, чтобы избежать бесконечного цикла в двунаправленных отношениях между объектами.
Мое описание не очень хорошее, надеюсь, оно вам поможет.
Это мой первый вклад в сообщество Java (решение вашей проблемы). Можете проверить;) Есть файл README.md https://github.com/trannamtrung1st/TSON
источник
В Android переполнение стека gson оказалось объявлением обработчика. Переместил его в класс, который не десериализуется.
По рекомендации Зара я сделал обработчик статическим, когда это произошло в другом разделе кода. Сделать обработчик статическим тоже сработало.
источник
BomItem
относится кBOMModule
(Collection<BomModule> modules
) иBOMModule
относится кBOMItem
(Collection<BomItem> items
). Библиотека Gson не любит циклические ссылки. Удалите эту циклическую зависимость из своего класса. Я тоже сталкивался с той же проблемой в прошлом с gson lib.источник
У меня возникла эта проблема, когда я поставил:
Logger logger = Logger.getLogger( this.getClass().getName() );
в моем объекте ... что имело смысл после часа отладки!
источник
Для пользователей Android вы не можете сериализовать объект
Bundle
из-за ссылки на себя,Bundle
вызывающейStackOverflowError
.Чтобы сериализовать пакет, зарегистрируйте файл
BundleTypeAdapterFactory
.источник
Избегайте ненужных обходных приемов, таких как установка значений на null или создание временных полей. Правильный способ сделать это - аннотировать одно из полей с помощью @Expose, а затем указать Gson сериализовать только поля с аннотацией:
private Collection<BomModule> parentModules; @Expose private Collection<BomModule> subModules; ... Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
источник
У меня была аналогичная проблема, когда в классе была переменная InputStream, которую мне действительно не нужно было сохранять. Следовательно, изменение его на Transient решило проблему.
источник
После некоторой борьбы с этой проблемой я считаю, что у меня есть решение. Проблема в неразрешенных двунаправленных соединениях и в том, как представлять соединения при их сериализации. Способ исправить такое поведение - «сказать»,
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
повторного ...Ответ основан на личном опыте, поэтому не стесняйтесь комментировать, чтобы доказать свою неправоту, исправить ошибки или расширить ответ. В любом случае я надеюсь, что кто-то сочтет этот ответ полезным.
источник