【问题标题】:Why does Jackson's PropertyGenerator prevent recursive loop为什么杰克逊的 PropertyGenerator 防止递归循环
【发布时间】:2016-01-25 09:07:06
【问题描述】:

我有两个双向映射的实体。具有一系列注册和注册本身的车辆。这些实体作为 REST 服务公开。

@Entity
@XmlRootElement
public class Vehicle implements Serializable {

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

  @OneToMany(mappedBy = "vehicle", fetch = FetchType.EAGER)
  private List<Registration> registrations;
}

问题在于 FetchType.EAGER 会产生无限递归

@Entity
@XmlRootElement
public class Registration implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;

  @ManyToOne
  private Vehicle vehicle;
}

经过一番研究,我发现我必须在 Vehicle 类中添加注释 @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") 才能解决问题。

我的问题是:PropertyGenerator 类实际上做了什么?

【问题讨论】:

    标签: java json rest jackson jax-rs


    【解决方案1】:

    问题不是因为FetchType.EAGERFetchType.EAGER 是 JPA 注释,当您使用 Jackson 序列化 Vehicle 实例时不会发挥作用。

    实际发生的是,Jackson 正在序列化车辆,这会触发注册列表的序列化,这会序列化具有注册列表的车辆,等等。

    正如您所注意到的,@JsonIdentityInfo 注释使无限递归短路,但这并不是因为您指定了特定的PropertyGenerator@JsonIdentityInfo 的 JavaDoc 提供了一些关于正在发生的事情的见解:

    @JsonIdentityInfo 用于指示带注释的类型或属性的值应该是序列化的注释,以便实例包含额外的对象标识符(除了实际的对象属性),或者作为包含引用完整序列化的对象 ID。在实践中,这是通过将第一个实例序列化为完整的对象和对象标识,以及对对象的其他引用作为引用值来完成的。

    换句话说,第一次序列化某些内容时,您将获得完整的序列化 JSON/XML 版本。下次序列化该对象时,您将获得对第一个序列化对象的引用。

    还有其他方法可以解决这个问题。查看Infinite Recursion with Jackson JSON and Hibernate JPA issue(您的问题可以说是这个问题的重复)。那里的答案建议您也可以使用@JsonIgnore@JsonManagedReference@JsonBackReference 的组合来避免无限递归。

    现在,关于PropertyGenerator 实际作用的具体问题:它指示Jackson 使用您的类中的特定属性作为对该对象完整序列化版本的引用。您将“id”指定为属性,因此在生成的序列化 JSON/XML 中,您应该看到,如果您有一个 ID 为 342 的对象,那么第一个序列化对象将显示 id 和所有其他序列化属性,但随后每次该对象是序列化你只会看到 342 序列化为对原始对象的引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      • 2012-07-21
      • 1970-01-01
      • 2014-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多