java - Jackson 循环依赖只是通过深度而不是同时通过深度和广度

标签 java json spring serialization jackson

我有一个类(class)用户:

@Entity
@Table(name = "User")
@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class User {

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

    @OneToMany(cascade = { CascadeType.ALL }, mappedBy = "user")
    private List<Car> cars;

    ...

}

还有一类汽车:

@Entity
public class Car {

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

    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, fetch = FetchType.EAGER)
    @JoinColumn(name = "userId", referencedColumnName = "id", nullable = false)
    private User user;

    ...

我有一个类 Car,它有一个用户,一个用户可以拥有多辆车。

问题是:

返回汽车列表时,想象汽车 A 和 B。

汽车 A 有用户 1,汽车 B 也有用户 1。

列表中的伪 json 序列化:

Car A {
  User 1 {
   id: 1
   Cars: {
    Car A: {
     User 1 {
      id: 1 just shows id 1 - correct in my way of thinking because it already looked into a user 1 and so here it needs to stop the circular dependency.
     }
    }
   }
  }
}
Car B {
  User 1 {
   id: 1 here in my way of thinking it should print the full user because in this level it didnt find one user on top but it seems it takes into consideration the first element of the list (car A) where it already found a User 1? Why? 
  }
}

我希望汽车 B 也拥有完整的用户。

看来 jackson 连载在深度和广度上都有效。

我希望它能够深入发挥作用。

基本上,由于用户 1 在返回第二辆车(广度)中的第一辆车(A 车)时已经被访问过,因此它只显示 B 车中的用户 1 id。

我希望 Jackson 在跳转到 B 车时会再次启动循环依赖检查。

我怎样才能实现这一目标?是否可以将 Jackson 配置为仅执行深度而不是广度的循环依赖检查?

预先感谢您的帮助。

----- 工作示例代码 -----

package com.guds.test;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.List;

public class test {

    public static void main(String... args) {

        User user1 = new User(1, "username 1");
        User user2 = new User(2, "username 2");
        Car car1 = new Car(1, "car 1", user1);
        Car car2 = new Car(2, "car 2", user1);
        Car car3 = new Car(3, "car 3", user2);
        Car car4 = new Car(4, "car 4", user2);

        user1.addGud(car1);
        user1.addGud(car2);

        user2.addGud(car3);
        user2.addGud(car4);

        List<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);

        List<Car> cars = new ArrayList<>();
        cars.add(car1);
        cars.add(car2);

        ObjectMapper om1 = new ObjectMapper();
        String json1 = null;
        try {
            json1 = om1.writeValueAsString(cars);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        System.out.println(json1);

        ObjectMapper om2 = new ObjectMapper();
        String json2 = null;
        try {
            json2 = om2.writeValueAsString(users);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        System.out.println(json2);

    }
}

车型:

package com.guds.test;


public class Car {

    private int id;
    private String name;

    private User user;

    public Car(int id, String name, User user) {
        this.id = id;
        this.name = name;
        this.user = user;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    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;
    }
}

类(class)用户:

package com.guds.test;


import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import java.util.ArrayList;
import java.util.List;

@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class User {

    private int id;
    private String name;

    List<Car> cars;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
        this.cars = new ArrayList<>();
    }

    public void addCar(Car car) {
        this.cars.add(car);
    }

    public int getId() {
        return id;
    }

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

    public List<Car> getCars() {
        return cars;
    }

    public void setCars(List<Car> cars) {
        this.cars = cars;
    }

    public String getName() {
        return name;
    }

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

在此程序的第一行输出中,您可以看到序列化汽车列表时会发生什么。

最佳答案

我忘了回答我自己的问题。我已经找到了解决方案。

简单的方法是使用@JsonIgnoreProperties。

我需要改变我的类(class):

package com.guds.test;


import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import java.util.ArrayList;
import java.util.List;

public class User {

    private int id;
    private String name;

    @JsonIgnoreProperties("user")
    List<Car> cars;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
        this.cars = new ArrayList<>();
    }

}

package com.guds.test;


public class Car {

    private int id;
    private String name;

    @JsonIgnoreProperties("cars")
    private User user;

    public Car(int id, String name, User user) {
        this.id = id;
        this.name = name;
        this.user = user;
    }
}

因此,在 User 类的情况下,当 Jackson 开始序列化它时,所有用户属性都被序列化,汽车列表和 Car 对象本身也被序列化,但因为我们说当 Jackson 序列化时忽略属性 user Car 对象它不会尝试序列化 Car 对象内的 User。

这样我们就打破了循环。

如果您从 Car 对象开始序列化,也会发生同样的情况。

而不是使用 @JsonIdentityInfo 注释时发生的情况,我们获取有关用户的所有信息及其汽车的所有信息(用户除外,但我们已经拥有有关用户的信息......),即使它们已经出现在连载过程中。

希望有帮助。

关于java - Jackson 循环依赖只是通过深度而不是同时通过深度和广度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57837450/

相关文章:

java - Hibernate 5 从表中获取某些列

javascript - 从 ajax.success() 调用 ajax.fail()

java - 与Gson的接口(interface)转换

java - 如何让mysql中的列保存Java类

java - 使用 Spring JDBC 获取 SQL 插入后生成的 key

javascript - 如何在请求服务器之前安全地转换列表参数过滤器

java - Java 客户端与 C# 类库之间的 Web 桥梁

在Maven中添加Selenium-java-2.31.0库后Java代码抛出异常

java - 如何通过单击第一个java Windows应用程序(Jframe)中的菜单项启动第二个Jframe

ios - 来自 iOS 主屏幕书签的 JSON-RPC 调用?