首页 > 解决方案 > 使用 @JsonIdentityInfo 时空 id 的无限递归

问题描述

我有 2 个 DTO 双向结构Category,多方关系Product在哪里。我想将它们作为 JSON 传输到前端层。当 id 已经分配(用于更新操作)时,我没有任何问题,但是当 id 为空(创建)时,我面临着众所周知的无限递归。Productone-to-manyREST

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="categoryId")
public class CategoryDTO implements Serializable {
    private Long categoryId;
    private String categoryName;
    private List<ProductDTO> products = new LinkedList<>();

    public void addProduct(ProductDTO product) {
        products.add(product);
        product.setCategory(this);
    }

    // remove synchronization method, setters, getters
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="productId")
public class ProductDTO implements Serializable {
    private Long productId;
    private String productName;
    private CategoryDTO category;

    // setters, getters
}

但是,当我使用时@JsonManagedReference@JsonBackReference一切都很好。我收到漂亮的 json:

{
   "categoryId":null,
   "categoryName":"category_name",
   "products": [
      {
         "productId":null,
         "productName":"product1"
      }
   ]
}
public class CategoryDTO implements Serializable {
    private Long categoryId;
    private String categoryName;

    @JsonManagedReference
    private List<ProductDTO> products = new LinkedList<>();

    public void addProduct(ProductDTO product) {
        products.add(product);
        product.setCategory(this);
    }

    // remove synchronization method, setters, getters
}
public class ProductDTO implements Serializable {
    private Long productId;
    private String productName;

    @JsonBackReference
    private CategoryDTO category;

    // setters, getters
}

在这两个示例中,其余部分如下:

@RestController
public class CategoryController {
    @GetMapping(path = "/categories")
    public ResponseEntity<CategoryDTO> fetchCategories() {
        CategoryDTO category = new CategoryDTO();
        category.setCategoryName("category_name");

        ProductDTO product1 = new ProductDTO();
        product1.setProductName("product1");

        category.addProduct(product1);

        return new ResponseEntity<>(category, HttpStatus.OK);
    }
}

为什么@JsonManagedReference@JsonBackReference工作,但@JsonIdentityInfo不工作?

谢谢阅读。

标签: javajsonspringjackson

解决方案


@JsonManagedReference并且@JsonBackReference正在使用对象实例引用,因此当您添加Product到时它可以工作Category,同时@JsonIdentityInfo使用字段值中的 id。

答案在课堂上WritableObjectIdBeanSerializerBase#_serializeWithObjectId(Object, JsonGenerator, SerializerProvider, boolean)

换句话说,对于非空字段,序列化程序记得,他序列化了给定的类实例,但他不能对空字段执行此操作。当您点击 endpoint 时,您可以看到这一点/categories。在连接中断之前,会生成无限的 JSON。

请有人纠正我,如果我错了。

注意: Imo 您应该删除字段private CategoryDTO category或将其更改为private Long categoryId,您将摆脱任何注释:D 此外,无限递归也不会有任何问题。


推荐阅读