消除Java Spring中的循环JSON多对多关系

时间:2016-12-31 11:31:00

标签: java json spring hibernate

我有一个Spring应用程序,其中包含两个具有多对多关系的实体。有学生和团体。学生可以成为许多团体的一部分,一个团体可以有很多学生。

学生模特

@Entity
@Table(name = "STUDENTS")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")

public class Student extends AbstractUser {

    //Fields

    @ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class)
    @JoinTable(name = "GROUPS_STUDENTS",
            joinColumns = { @JoinColumn(name = "student_id") },
            inverseJoinColumns = { @JoinColumn(name = "group_id") })
    private List<Group> groups = new ArrayList<Group>();

    //Constructors

    public Student(String password, String firstName, String lastName, String email){
        super(password, firstName, lastName, email);
    }

    public Student(){
    }

    //Setters and getters

    public List<Group> getGroups() {
        return groups;
    }

    public void setGroups(List<Group> groups) {
        this.groups = groups;
    }

}

群组模型

@Entity
@Table(name = "GROUPS")
@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class Group implements Item, Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false, unique = true)
    private String name;

    @Column(name = "year", nullable = false, length = 1)
    private int year;

    @ManyToMany(mappedBy = "groups", targetEntity = Student.class)
    private List<Student> students;

    public Group(String name, int yearOfStudy) {
        this.setName(name);
        this.setYear(yearOfStudy);
    }
...
}

问题在于,当我向所有学生发出请求时,如果2名学生在同一组中,则他们出现在层次结构中而不是一个接一个。我的意思是JSON太深了。我不知道如何准确解释,但我会举一个例子。

如何显示

&#13;
&#13;
[
  {
    "id": 2,
    "password": "$2a$10$bxieGA7kWuEYUUMbYNiYo.SbGpo7X5oh8ulUsqCcrIR2cFN2HiQP2",
    "firstName": "First",
    "lastName": "Last",
    "email": "name@mail.com",
    "groups": [
      {
        "id": 1,
        "name": "G1",
        "year": 0,
        "users": [
          2,
          {
            "id": 1,
            "password": "$2a$10$9pfTdci7PeHtzxuAxjcOsOjPSswrU35/JOOeWPpgVhJI4tD2YpZdG",
            "firstName": "John",
            "lastName": "Smith",
            "email": "john.smith@mail.com",
            "groups": [
              1
            ]
          }
        ]
      }
    ]
  },
  1
]
&#13;
&#13;
&#13;

应该如何显示

&#13;
&#13;
  {
    "id": 2,
    "password": "$2a$10$bxieGA7kWuEYUUMbYNiYo.SbGpo7X5oh8ulUsqCcrIR2cFN2HiQP2",
    "firstName": "First",
    "lastName": "Last",
    "email": "name@mail.com",
    "groups": [
      {
        "id": 1,
        "name": "G1",
        "year": 0,
      }
    ]
  },
  {
    "id": 1,
    "password": "$2a$10$9pfTdci7PeHtzxuAxjcOsOjPSswrU35/JOOeWPpgVhJI4tD2YpZdG",
    "firstName": "John",
    "lastName": "Smith",
    "email": "john.smith@mail.com",
    "groups": [
      {
        "id": 1,
        "name": "G1",
        "year": 0
      }]
  }
]
&#13;
&#13;
&#13;

你知道如何解决这个问题吗?我不知道如何描述我的问题,以及为什么我还没有找到解决方案。任何帮助将非常感谢。谢谢。

5 个答案:

答案 0 :(得分:3)

使用@JsonIgnoreProperties注释是另一种选择:

@Entity
public class Student extends AbstractUser {
    @ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class)
    @JoinTable(name = "GROUPS_STUDENTS",
            joinColumns = { @JoinColumn(name = "student_id") },
            inverseJoinColumns = { @JoinColumn(name = "group_id") })
    @JsonIgnoreProperties("students")
    private List<Group> groups = new ArrayList<Group>();
}

@Entity
public class Group implements Item, Serializable {
    @ManyToMany(mappedBy = "groups", targetEntity = Student.class)
    @JsonIgnoreProperties("groups")
    private List<Student> students;
}

在此处找到@JsonManagedReference + @JsonBackReference@JsonIdentityInfo@JsonIgnoreProperties之间的比较:http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html

答案 1 :(得分:0)

要解决杰克逊无限递归问题,您可以使用.row{ transition-property: top; transition-duration:0.5s; } @JsonManagedReference

  

@JsonManagedReference是引用的前向部分 - 那个   正常序列化。

     

@JsonBackReference是后面的部分   参考 - 它将从序列化中省略。

在此处查找更多详情:http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion

@JsonBackReference

答案 2 :(得分:0)

如果您希望能够动态定义必须序列化的内容,您可以尝试我根据此处提出的问题开发的jackson插件:

https://stackoverflow.com/a/28245875/869225

这也帮助我进行反向推理。

答案 3 :(得分:0)

我已经解决了。我做了一个自定义序列化程序。所以在第一组中,我会通过设置自定义注释序列化学生 @JsonSerialize(using = CustomStudentSerializer.class)

<强> CustomStudentSerializer

public class CustomStudentSerializer extends StdSerializer<List<Student>> {

    public CustomStudentSerializer() {
        this(null);
    }

    public CustomStudentSerializer(Class<List<Student>> t) {
        super(t);
    }

    @Override
    public void serialize(
            List<Student> students,
            JsonGenerator generator,
            SerializerProvider provider)
            throws IOException, JsonProcessingException {

        List<Student> studs = new ArrayList<>();
        for (Student s : students) {
            s.setGroups(null);
            studs.add(s);
        }
        generator.writeObject(studs);
    }
}

对团体做了同样的事情。当关系已经嵌套时,我刚刚删除了学生/组组件。现在它的工作正常。

我花了一些时间来解决这个问题,但我发布在这里因为它也可以帮助其他人。

答案 4 :(得分:0)

或者您可以使用DTO(数据传输对象)类。这些是简单的代码类,您可以在sendind数据时根据需要进行设置。例如,对于您的情况,您可以:

UserDTO.java:

import java.util.List;

public class UserDTO {

    private int id;

    private String password;

    private String firstName;

    private String lastName;

    private String email;

    private List<GroupDTO> groups;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public List<GroupDTO> getGroups() {
        return groups;
    }

    public void setGroups(List<GroupDTO> groups) {
        this.groups = groups;
    }

}

GroupDTO.java

package temp;

public class GroupDTO {

    private int id;

    private String name;

    private int year;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

}

这样您就可以自定义要在json文件中发送的信息。

假设您有一个User类,并且您希望向所有用户发送信息:

    List<StudentDTO> response = new ArrayList<StudentDTO>(); //List to be send

    List<Student> students = bussinessDelegate.findAllStudents(); //Or whatever you do to get all students

    for (int i = 0; i < students.size(); i++) {

        Student student = students.get(i);          

        StudentDTO studentDTO = new StudentDTO(); //Empty constructor

        studentDTO.setEmail(student.getEmail());
        studentDTO.setFirstName(student.getFirstName());
        studentDTO.setLastName(student.getLastName());
        studentDTO.setId(student.getId());
        studentDTO.setPassword(student.getPassword());

        List<Group> studentGroups = student.getGroups();

        List<GroupDTO> studentGroupsDTO = new ArrayList<GroupDTO>();

        for (int j = 0; j < studentGroups.size(); j++) {

            Group group = studentGroups.get(j);

            GroupDTO groupDTO = new GroupDTO();

            groupDTO.setId(group.getId());
            groupDTO.setName(group.getName());
            groupDTO.setYear(group.getYear());

            studentGroupsDTO.add(groupDTO);

        }

        studentDTO.setGroups(studentGroupsDTO);
        response.add(studentDTO);
    }

    //Here you have your response list of students ready to send`