гсон.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;


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

670   11  

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

    Ничего не найдено.