Получение запроса с ассоциацией «многие ко многим» в Hibernate, похоже, ведет к бесконечному циклу - PullRequest
0 голосов
/ 12 января 2019

У меня есть отношение многие ко многим в Hibernate, и когда я пытаюсь получить данные с помощью @GetMapping, я получаю сообщение об ошибке.

На сервере трудно найти сообщение об ошибке, так как я не могу прокрутить достаточно далеко на консоли (увеличение буфера на IntelliJ не помогло).

На внешнем интерфейсе (в Angular), где я пытаюсь получить данные, я получаю сообщение 200 OK с ошибкой и без данных. Ошибка SyntaxError: "JSON.parse: end of data after property value in object at line 1 column 82277 of the JSON data", а текст следующий:

"[{\"speciesId\":1,\"attributes\":[{\"attributesId\":1,\"species\":[{\"speciesId\":1,\"attributes\":[{\"attributesId\":1,\"species\":[{\"speciesId\":1,\"attributes\":[{\"attributesId\":1,\"species\":[{\"speciesId\":1,\"attributes\":[{\"attributesId\":1,\"species\":[{\"speciesId\":1,\"attributes\":[{\"attributesId\":1,\"species\":[{\"speciesId\":1,\"attributes\":[{\"attributesId\":1,\"species\":[{\"speciesId

, но продолжается намного дольше, и после этого:

{\"timestamp\":\"2019-01-12T14:49:20.913+0000\",\"status\":200,\"error\":\"OK\",\"message\":\"Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.hibernate.collection.internal.PersistentSet[0]->com.example.demo.model.Species[\\\"attributes\\\"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.demo.model.Attributes[\\\"species\\\"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.demo.model.Species[\\\"attributes\\\"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.demo.model.Attributes[\\\"species

Снова продолжается намного дольше, чем это.

StackOverflowError и длинная строка одного и того же текста заставляют меня поверить, что в @GetMapping Hibernate заканчивается бесконечным циклом.

Два связанных класса - это Атрибуты и Виды.

Атрибуты:

@Entity
@Table(name= "Attributes")
public class Attributes {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int attributesId;

    @ManyToMany()
    @JoinTable (
            name = "Species_Attributes",
            joinColumns = { @JoinColumn(name = "attributesId")},
            inverseJoinColumns = { @JoinColumn(name= "speciesId")}
    )
    @OnDelete(action = OnDeleteAction.CASCADE)
    Set<Species> species = new HashSet<>();

    @NotNull
    @Column
    String attribute;

    @NotNull
    @Column
    String value;

    public void addSpecies(Species s) {
        this.species.add(s);
        s.getAttributes().add(this);
    }

    [...]
}

Вид:

@Entity
@Table(name="Species")
public class Species {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int speciesId;

    @ManyToMany(mappedBy = "species")
    private Set<Attributes> attributes = new HashSet<>();

    @NotNull
    @Column
    String species;

    @NotNull
    @Column
    String description;

    public void addAttribute(Attributes a) {
        this.attributes.add(a);
        a.getSpecies().add(this);
    }

    [...]
}

Запрос на получение:

@GetMapping("/speciesdb")
    Iterable<Species> showSpecies(){
        return speciesService.findAll();
    }

Я могу поместить данные в свою базу данных. Я проверил все таблицы, включая таблицу kind_attributes, и все они содержат правильные данные. Если у вида еще нет атрибутов, получение данных работает, как и ожидалось, без ошибок. Только когда я добавляю атрибут, я получаю эту ошибку.

Edit: Если я удаляю функции addSpecies() и addAttribute(), очищаю и пополняю таблицы, я больше не получаю ошибку. Теперь, если я get видов, список атрибутов будет пустым.

1 Ответ

0 голосов
/ 12 января 2019

Это потому, что ваши Виды и Атрибут связаны друг с другом, что иногда может вызвать бесконечный цикл. Например, ваш граф объектов может выглядеть следующим образом:

enter image description here

Предположим, вы используете Джексона для сериализации в JSON, вы можете использовать @JsonIgnoreProperties, чтобы разорвать циклы:

@Entity
@Table(name= "Attributes")
public class Attributes {

    [.....]
    @JsonIgnoreProperties("attributes")
    Set<Species> species = new HashSet<>();

    [...]
}   

@Entity
@Table(name="Species")
public class Species {

    [....]
    @JsonIgnoreProperties("species")
    private Set<Attributes> attributes = new HashSet<>();

    [...]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...