Postman发送POST请求时Jackson反序列化ProductDto报错求助
问题描述
Postman发送POST请求时触发JSON解析错误:
无法构造
HogeschoolLeiden.IPRWCApp.product.ProductDto实例(尽管存在至少一个构造器):没有int/Int参数的构造器/工厂方法来从数值10进行反序列化;嵌套异常为com.fasterxml.jackson.databind.exc.MismatchedInputException,错误源于OrderItemDto["product"]的引用链。
相关代码
Product实体类
@Entity @Table(name = "product") @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Product { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "product_name", columnDefinition = "TEXT", nullable = false, unique = true) private String productName; @Column(name = "product_photo", columnDefinition = "TEXT") private String productPhoto; @Column(name = "product_prise", columnDefinition = "INT", nullable = false) private int productPrise; @Column(name = "product_description", columnDefinition = "TEXT") private String productDescription; }
ProductDto类
@Getter @Setter public class ProductDto { private Long productId; private String productName; private String productPhoto; private int productPrise; private String productDescription; }
OrderItem实体类
@Entity @Table(name = "ORDER_ITEM") @Data @Builder @NoArgsConstructor @AllArgsConstructor public class OrderItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(targetEntity = Product.class, fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "product", referencedColumnName = "id", updatable = false, nullable = false) private Product product; @Column(name = "quantity", nullable = false) private int quantity; @CreationTimestamp @Column(name = "created_at", nullable = false, updatable = false) private Date createdAt; @UpdateTimestamp @Column(name = "updated_at") private Date updatedAt; @ManyToOne @JoinColumn(name = "order_id", nullable = false) private Order orderCart; }
OrderItemDto类
@Getter @Setter public class OrderItemDto { private Long id; private ProductDto product; private int quantity; private Date createdAt; private Date updatedAt; private Order orderCart; }
OrderItemService类
@Service @Transactional @RequiredArgsConstructor @AllArgsConstructor @Slf4j public class OrderItemService { @Autowired private ProductRepo productRepo; @Autowired private OrderItemRepo orderItemRepo; @Autowired private OrderItemMapper orderItemMapper; public OrderItemDto addProductToCart(OrderItemDto orderItemDto) { OrderItem orderItem = orderItemMapper.toOrderItem(orderItemDto); // Product producty = productRepo.findProductById(orderItemDto.getProduct().getProductId()); // OrderItem orderItem = OrderItem.builder() // .product(producty) // .quantity(orderItemDto.getQuantity()) // .appUser(orderItemDto.getAppUser()) // .build(); log.info("Saving new Order-Item: {} to the database.", orderItem.getProduct().getId()); if (orderItem.getProduct().getId() != null) { orderItemRepo.save(orderItem); return orderItemMapper.toDTO(orderItem); } throw new ResponseStatusException( HttpStatus.BAD_REQUEST, "Order-Item with order-id: " + orderItem.getId() + " doesn't exist between products." ); } public List<OrderItemDto> getAllOrderItemsDto() { List<OrderItem> orderItemList = orderItemRepo.findAll(); log.info(orderItemList.toString()); return orderItemMapper.toDTOs(orderItemList); } public OrderItemDto getOrderItemDto(Long id) { OrderItem orderItem = getOrderItem(id); return orderItemMapper.toDTO(orderItem); } private OrderItem getOrderItem(Long id) { return orderItemRepo.findById(id).orElseThrow(()-> new ResponseStatusException(HttpStatus.NOT_FOUND) ); } public void deleteOrderItem(Long id){ if (!orderItemRepo.existsById(id)) { throw new ResponseStatusException( HttpStatus.BAD_REQUEST, "No OrderItem found with id: " + id); } orderItemRepo.deleteById(id); } }
原因分析
核心问题是你发送的POST请求JSON中,product字段传的是单个数值(比如10),但OrderItemDto里的product字段定义为ProductDto类型。Jackson尝试将这个数值直接反序列化为ProductDto对象,但ProductDto没有接收单个int/long类型参数的构造器或工厂方法,因此抛出反序列化不匹配的错误。
举个例子,你可能传递了如下错误格式的JSON:
{ "product": 10, "quantity": 2 }
解决思路
方案1:调整POST请求的JSON格式(适配现有DTO结构)
如果业务需要传递完整的ProductDto对象,JSON必须符合ProductDto的结构,示例如下:
{ "product": { "productId": 10, "productName": "示例商品", "productPrise": 99, // 其他ProductDto字段按需填写 }, "quantity": 2, "orderCart": { // 对应Order对象的结构 } }
方案2:修改OrderItemDto字段定义(更贴合业务逻辑)
实际购物车添加商品的场景中,通常只需要传递产品ID即可,无需完整的产品对象。这种情况下推荐修改OrderItemDto:
- 将
private ProductDto product;替换为private Long productId; - 在Service层通过
productId查询对应的Product实体,再组装OrderItem
修改后的OrderItemDto:
@Getter @Setter public class OrderItemDto { private Long id; private Long productId; // 替换原ProductDto字段 private int quantity; private Date createdAt; private Date updatedAt; private Order orderCart; }
调整addProductToCart方法逻辑:
public OrderItemDto addProductToCart(OrderItemDto orderItemDto) { // 根据productId查询产品,不存在则抛出404 Product product = productRepo.findById(orderItemDto.getProductId()) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "指定产品不存在")); // 构建OrderItem对象 OrderItem orderItem = OrderItem.builder() .product(product) .quantity(orderItemDto.getQuantity()) .orderCart(orderItemDto.getOrderCart()) .build(); log.info("Saving new Order-Item: {} to the database.", product.getId()); orderItemRepo.save(orderItem); return orderItemMapper.toDTO(orderItem); }
方案3:给ProductDto添加单参数构造器(不推荐)
如果坚持要通过数值直接反序列化ProductDto,可以给ProductDto添加接收productId的构造器,但这种方式会让DTO语义模糊,不符合分层设计原则,仅作备选:
@Getter @Setter public class ProductDto { private Long productId; private String productName; private String productPhoto; private int productPrise; private String productDescription; // 添加接收productId的构造器 public ProductDto(Long productId) { this.productId = productId; } // 保留无参构造器(Jackson反序列化需要) public ProductDto() {} }
内容的提问来源于stack exchange,提问作者H. Motsu

