多对一:JSON 解析错误无法构造实例
Many-To-One : JSON parse error Cannot construct instance
我开发了一个 REST API 使用 spring 启动
我有两个具有双向 OneToMany
的实体
产品class
public class Product {
private Long productId;
private String name;
private String description;
private List<ProductList> productList;
public Product() {
}
public Product(Long productId, String name, String description, List<ProductList> productList) {
this.productId = productId;
this.name = name;
this.description = description;
this.productList = productList;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<ProductList> getProductList() {
return productList;
}
public void setProductList(List<ProductList> productList) {
this.productList = productList;
}
产品列表class
public class ProductList {
private Long productListId;
private String productListName;
private Product product;
public ProductList(Long productListId, String productListName, Product product) {
this.productListId = productListId;
this.productListName = productListName;
this.product = product;
}
public ProductList() {
}
public Long getProductListId() {
return productListId;
}
public void setProductListId(Long productListId) {
this.productListId = productListId;
}
public String getProductListName() {
return productListName;
}
public void setProductListName(String productListName) {
this.productListName = productListName;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
ProductEntity class:
@Entity
@Data
@Table(name = "PRODUCT")
public class ProductEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer productId;
@Column
private String name;
@Column
private String description;
@OneToMany(cascade = CascadeType.ALL, mappedBy="product", fetch =
FetchType.EAGER)
private List<ProductListEntity> productList;
// Getters,Setters,No-ArgCOnstructor, All-ArgConstructor
ProductListEntity class:
@Table
@Entity
@Data
public class ProductListEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long productListId;
private String productListName;
@ManyToOne(fetch = FetchType.EAGER, targetEntity = ProductEntity.class)
@JoinColumn(name = "FK_Product", referencedColumnName = "productId")
private ProductEntity product;
保存数据服务:
public void addProduct(Product product) {
ProductEntity productEntity = new ProductEntity();
BeanUtils.copyProperties(product, productEntity);
productRepository.save(productEntity);
}
当我尝试 post 时出现此错误:
"message": "JSON parse error: Cannot construct instance of
eteosf.hexagonal.domain.model.Product
(although at least one Creator
exists): no String-argument constructor/factory method to deserialize
from String value ('string'); nested exception is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot
construct instance of eteosf.hexagonal.domain.model.Product
(although at least one Creator exists): no String-argument
constructor/factory method to deserialize from String value
('string')\n at [Source: (PushbackInputStream); line: 9, column: 18]
(through reference chain:
eteosf.hexagonal.domain.model.Product["productList"]->java.util.ArrayList[0]->eteosf.hexagonal.domain.model.Product$ProductList["product"])",
"path": "/product"
JSON 请求正文:
{
"productId": 0,
"name": "string",
"description": "string",
"productList": [
{
"productListId": 0,
"productListName": "string",
"product": "string"
}
]
}
在您的 json_request 中,您在 productList 中将“产品”作为“字符串”发送。但是 Deserializer 不能将该字符串转换为 Product 对象。它必须作为对象 {}
发送。您可以将该对象留空 - 如果它所做的只是指向自身,则不发送它。
你基本上犯了一个混淆不同原则的错误——整个双向关系只适用于持久层。 Json 请求在 controller/view 级别发送,因此您无法以相同的方式显示双向性质。这就是为什么您不使用实体作为控制器参数而是使用 DTO 的原因。
在你的情况下,不要为控制器发送“产品”字段:
{
"productId": 0,
"name": "string",
"description": "string",
"productList": [
{
"productListId": 0,
"productListName": "string",
}
]
}
收到参数后直接在controller方法中添加:
//the receiving controller method which got Parameter `ProductEntity product`
product.getProductList().forEach(productList -> productList.setProduct(product);
就像我说的,你不应该在 Controller 方法中使用实体,它应该是一个 DTO class 为了避免这种问题
我开发了一个 REST API 使用 spring 启动 我有两个具有双向 OneToMany
的实体产品class
public class Product {
private Long productId;
private String name;
private String description;
private List<ProductList> productList;
public Product() {
}
public Product(Long productId, String name, String description, List<ProductList> productList) {
this.productId = productId;
this.name = name;
this.description = description;
this.productList = productList;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<ProductList> getProductList() {
return productList;
}
public void setProductList(List<ProductList> productList) {
this.productList = productList;
}
产品列表class
public class ProductList {
private Long productListId;
private String productListName;
private Product product;
public ProductList(Long productListId, String productListName, Product product) {
this.productListId = productListId;
this.productListName = productListName;
this.product = product;
}
public ProductList() {
}
public Long getProductListId() {
return productListId;
}
public void setProductListId(Long productListId) {
this.productListId = productListId;
}
public String getProductListName() {
return productListName;
}
public void setProductListName(String productListName) {
this.productListName = productListName;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
ProductEntity class:
@Entity
@Data
@Table(name = "PRODUCT")
public class ProductEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer productId;
@Column
private String name;
@Column
private String description;
@OneToMany(cascade = CascadeType.ALL, mappedBy="product", fetch =
FetchType.EAGER)
private List<ProductListEntity> productList;
// Getters,Setters,No-ArgCOnstructor, All-ArgConstructor
ProductListEntity class:
@Table
@Entity
@Data
public class ProductListEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long productListId;
private String productListName;
@ManyToOne(fetch = FetchType.EAGER, targetEntity = ProductEntity.class)
@JoinColumn(name = "FK_Product", referencedColumnName = "productId")
private ProductEntity product;
保存数据服务:
public void addProduct(Product product) {
ProductEntity productEntity = new ProductEntity();
BeanUtils.copyProperties(product, productEntity);
productRepository.save(productEntity);
}
当我尝试 post 时出现此错误:
"message": "JSON parse error: Cannot construct instance of
eteosf.hexagonal.domain.model.Product
(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('string'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance ofeteosf.hexagonal.domain.model.Product
(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('string')\n at [Source: (PushbackInputStream); line: 9, column: 18] (through reference chain: eteosf.hexagonal.domain.model.Product["productList"]->java.util.ArrayList[0]->eteosf.hexagonal.domain.model.Product$ProductList["product"])", "path": "/product"
JSON 请求正文:
{
"productId": 0,
"name": "string",
"description": "string",
"productList": [
{
"productListId": 0,
"productListName": "string",
"product": "string"
}
]
}
在您的 json_request 中,您在 productList 中将“产品”作为“字符串”发送。但是 Deserializer 不能将该字符串转换为 Product 对象。它必须作为对象 {}
发送。您可以将该对象留空 - 如果它所做的只是指向自身,则不发送它。
你基本上犯了一个混淆不同原则的错误——整个双向关系只适用于持久层。 Json 请求在 controller/view 级别发送,因此您无法以相同的方式显示双向性质。这就是为什么您不使用实体作为控制器参数而是使用 DTO 的原因。
在你的情况下,不要为控制器发送“产品”字段:
{
"productId": 0,
"name": "string",
"description": "string",
"productList": [
{
"productListId": 0,
"productListName": "string",
}
]
}
收到参数后直接在controller方法中添加:
//the receiving controller method which got Parameter `ProductEntity product`
product.getProductList().forEach(productList -> productList.setProduct(product);
就像我说的,你不应该在 Controller 方法中使用实体,它应该是一个 DTO class 为了避免这种问题