Подтвердить что ты не робот

Сериализация двунаправленных объектов JPA для JSON с помощью джексона

Я использую Jackson для сериализации моей модели JPA в JSON.

У меня есть следующие классы:

import com.fasterxml.jackson.annotation.*;
import javax.persistence.*;
import java.util.Set;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
@Entity
public class Parent {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String name;

  @JsonManagedReference
  @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  private Set<Child> children;

  //Getters and setters
}

и

import com.fasterxml.jackson.annotation.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
@Entity
public class Child {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String name;

  @JsonBackReference
  @ManyToOne
  @JoinColumn(name = "parentId")
  private Parent parent;

  //Getters and setters
}

Я использую сопоставление POJO для сериализации из модели в JSON. Когда я сериализую объект Parent, я получаю следующий JSON:

{
  "id": 1,
  "name": "John Doe",
  "children": [
    {
      "id": 1,
      "name": "child1"
    },{
      "id": 2,
      "name": "child2"
    }
  ]
}

Но когда я сериализую Child, я получаю следующий JSON:

{
  "id": 1,
  "name": "child1"
}

Отсутствует ссылка на родителя. Есть ли способ решить это?

4b9b3361

Ответ 1

Я думаю, вам нужно выбрать между @JsonIdentityInfo и @JsonBackReference/@JsonManagedReference.

Я бы пошел с: @JsonIdentityInfo (generator = ObjectIdGenerators.PropertyGenerator.class, property = "id" ) на ваших сущностях, удаляет пары @JsonBackReference/@JsonManagedReference.

И добавьте @JsonIgnore в поля, которые вы хотите исключить.

Ответ 2

Вы можете использовать JsonManagedReference/JsonBackReference и в то же время использовать JsonIdentityInfo для дополнения двунаправленных отношений.

В вопросе Класс:

// bi-directional one-to-many association to Answer (Question is owner)
@JsonManagedReference
@OneToMany(mappedBy = "question", cascade = CascadeType.ALL)
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@QuestionAnswers")
private Set<Answer> answers = new HashSet<>();

В ответе Класс: // двунаправленная ассоциация "много-к-одному" с вопросом

@JsonBackReference
@ManyToOne
@JoinColumn(name = "questionId", referencedColumnName="id", foreignKey = @ForeignKey(name = "fk_answer_question"))
private Question question;

Если вам нужна родительская ссылка в дочернем объекте, удалите ссылку Managed/Back Reference, это отлично работает для меня.

Ответ 3

Проблема заключается в том, что использование управляемых/обратных ссылок требует, чтобы направление обхода всегда было от родительского к дочернему (т.е. сначала использовало управляемую ссылку). Это ограничение для этих аннотаций.

Как следует из другого ответа, использование идентификаторов объектов является более гибкой альтернативой, которая может работать.

Еще одна возможность, которая могла бы работать, - использовать JSON Views или JSON Filter для условного включения/исключения родительской ссылки, если вы можете разделить случаи. Это может стать беспорядочным.

Ответ 4

Вы можете использовать @JsonBackReference/@JsonManagedReference и добавить этот метод к дочернему

@JsonProperty
public Long getParentId() {
    return parent == null ? null : parent.getId();
}

Результат будет:

{
  "id": 1,
  "name": "child1",
  "parentId": 1
}

Я надеюсь, что это поможет кому-то.