гсон.toJson () бросает StackOverflowError
Я хотел бы создать строку 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.write(TypeAdapters.java:235)
at com.google.gson.internal.bind.TypeAdapters.write(TypeAdapters.java:220)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.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;
любая идея, что вызывает эту ошибку? Как я могу это исправить?
11 ответов:
эта проблема заключается в том, что у вас есть круговая ссылка.
на
BomModuleкласс, на который вы ссылаетесь:private Collection<BomModule> parentModules; private Collection<BomModule> subModules;это само ссылка на
BomModule, очевидно, не нравится GSON вообще.обходной путь просто установить модули в
nullчтобы избежать рекурсивного цикла. Таким образом, я могу избежать исключения StackOverFlow.item.setModules(null);или отметьте поля вы не хочу для отображения в сериализованном json с помощью
transientключевое слово, например:private transient Collection<BomModule> parentModules; private transient Collection<BomModule> subModules;
у меня была эта проблема, когда у меня был log4j logger как свойство класса, например:
private Logger logger = Logger.getLogger(Foo.class);Это можно решить, либо сделав регистратор
staticили просто переместив его в фактическую функцию(ы).
как сказал Слакс 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();
Если вы используете Realm и вы получаете эту ошибку, а объект, дающий проблемы, расширяет RealmObject, не забудьте сделать
realm.copyFromRealm(myObject)чтобы создать копию без всех Привязок области перед передачей в GSON для сериализации.Я пропустил это только для одного из множества копируемых объектов... мне потребовались годы, чтобы понять, как трассировка стека не называет класс/тип объекта. Дело в том, что проблема вызвана круговой ссылкой, но это круговая ссылка где-то в базовом классе RealmObject, а не в вашем собственном подклассе, что затрудняет его обнаружение!
мой ответ немного запоздал, но я думаю, что этот вопрос еще не имеет хорошего решения. Я нашел его изначально здесь.
С помощью Gson вы можете отметить поля, которые вы do хотите быть включены в JSON с
@Exposeтакой:@Expose String myString; // will be serialized as myStringи создать объект gson с помощью:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();циклические ссылки вы просто не выставить. Что сделал трюк для меня!
эта ошибка распространена, когда у вас есть регистратор в вашем супер классе. Как @ Zar предложил раньше, вы можете использовать статический для вашего поля регистратора, но это также работает:
protected final transient Logger logger = Logger.getLogger(this.getClass());P. S. наверное это будет работать и с @подвергайте проверке аннотации подробнее об этом здесь: https://stackoverflow.com/a/7811253/1766166
у меня та же проблема. В моем случае причиной было то, что конструктор моего сериализованного класса принимает контекстную переменную, например:
public MetaInfo(Context context)когда я удаляю этот аргумент, ошибка исчезла.
public MetaInfo()
в Android переполнение стека gson оказалось объявлением обработчика. Переместил его в класс, который не десериализуется.
основываясь на рекомендации Zar, я сделал обработчик статическим, когда это произошло в другом разделе кода. Создание статического обработчика также работало.
BomItemотносится кBOMModule(Collection<BomModule> modules), иBOMModuleотносится кBOMItem(Collection<BomItem> items). Библиотека Gson не любит циклические ссылки. Удалите эту циклическую зависимость из класса. Я тоже сталкивался с такой же проблемой в прошлом с Gson lib.
У меня эта проблема возникла для меня, когда я поставил:
Logger logger = Logger.getLogger( this.getClass().getName() );в моем объекте...что имело смысл после часа или около отладка!
Edit: извините за мой плохой, это мой первый ответ. Спасибо за Ваши советы.
Я создаю свой собственный конвертер Json
основное решение, которое я использовал, - это создать родительский набор объектов для каждой ссылки на объект. Если суб-ссылка указывает на существующий родительский объект, она будет отброшена. Затем я комбинирую с дополнительным решением, ограничивая опорное время, чтобы избежать инфинитивного цикла в двунаправленных отношениях между сущностями.
мое описание не слишком хорошо, надеюсь, это поможет вам, ребята.
Это мой первый вклад в сообщество Java (решение вашей проблемы). Вы можете проверить это ;) Там есть ридми.файл MD https://github.com/trannamtrung1st/TSON
Comments