Вебинары Разобраться в IT Реферальная программа
Программирование Аналитика Дизайн Маркетинг Управление проектами
7 профессий по цене одной
07:05:47:06
дн. ч. мин. сек.
24 Авг 2023
2 мин
638

Бесконечная рекурсия с Jackson JSON и Hibernate JPA

Одной из распространённых проблем в Java, с которой сталкиваются разработчики, работающие с Hibernate JPA и Jackson JSON, является ошибка бесконечной рекурсии или

Одной из распространённых проблем в Java, с которой сталкиваются разработчики, работающие с Hibernate JPA и Jackson JSON, является ошибка бесконечной рекурсии или Infinite recursion. Эта проблема обычно возникает при попытке преобразовать объект JPA, имеющий двунаправленную ассоциацию, в JSON.

Ошибка бесконечной рекурсии обычно выглядит следующим образом:

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

Эта проблема происходит из-за того, что при сериализации объекта с двунаправленной ассоциацией, Jackson пытается сериализовать оба объекта взаимно, что приводит к бесконечной рекурсии.

Рассмотрим пример. Предположим, у нас есть два класса Person и Car, связанные двунаправленной ассоциацией:

public class Person {
    private String name;
    private Car car;
    //getters and setters
}

public class Car {
    private String model;
    private Person owner;
    //getters and setters
}

В случае попытки сериализации объекта Person в JSON, Jackson пытается сериализовать связанный с ним объект Car. Но т.к. Car также ссылается на Person, Jackson пытается сериализовать Person еще раз и так далее.

Однако, существуют способы обойти эту проблему, не избегая использования двунаправленных ассоциаций.

Один из способов — использовать аннотации @JsonManagedReference и @JsonBackReference библиотеки Jackson:

public class Person {
    private String name;

    @JsonManagedReference
    private Car car;
    //getters and setters
}

public class Car {
    private String model;

    @JsonBackReference
    private Person owner;
    //getters and setters
}

В данном случае @JsonManagedReference указывает на то, что поле должно быть сериализовано, а @JsonBackReference указывает на то, что поле должно быть пропущено во время сериализации.

Ещё одним решением проблемы может быть использование аннотации @JsonIgnore для пропуска определенного поля при сериализации:

public class Car {
    private String model;

    @JsonIgnore
    private Person owner;
    //getters and setters
}

Таким образом, поле owner будет пропущено при сериализации объекта Car, что предотвратит возникновение бесконечной рекурсии.

Также можно использовать аннотацию @JsonIdentityInfo, которая позволяет обрабатывать циклические зависимости в данных, сохраняя идентификаторы объектов вместо их сериализации:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id")
public class Person {
    private String name;
    private Car car;
    //getters and setters
}

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id")
public class Car {
    private String model;
    private Person owner;
    //getters and setters
}

В этом случае, вместо сериализации объекта Person при сериализации объекта Car будет сохранен только идентификатор Person. Это также предотвратит возникновение бесконечной рекурсии.

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей

Добавить комментарий