Spring序列化JSON报错:无法实例化BillsKey复合主键实体
复合主键类BillsKey实例化失败问题解决
问题场景
使用BillsKey作为Bills实体类的复合主键,已添加Lombok的@NoArgsConstructor、@AllArgsConstructor、@Data注解,但仍出现JSON序列化失败的报错,提示无法实例化BillsKey。
相关代码
BillsKey类
@NoArgsConstructor @AllArgsConstructor @Data public class BillsKey implements Serializable { private Suppliers supplier; private int id; }
Bills实体类
@Data @Table(schema = "PharmaPal", name = "Bills") @Entity @Builder @NoArgsConstructor @AllArgsConstructor @IdClass(BillsKey.class) public class Bills { @Id private Long id; @ManyToOne @Id @JoinColumn(name = "supplier", foreignKey = @ForeignKey(name = "fk_supplier")) private Suppliers supplier; @Temporal(TemporalType.DATE) private LocalDate billDate; private double total; @Temporal(TemporalType.DATE) private LocalDate dueDate; private String State; @OneToMany(mappedBy = "bills", cascade = CascadeType.ALL) private Set<StockedProducts> stockedProducts; }
报错信息
2024-04-17T16:17:23.036+01:00 WARN 8124 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: 无法写入JSON:无法实例化实体: com.example.pharmapal.Entities.Compositekeys.BillsKey]
问题分析
- 类型不匹配:
Bills实体中的id字段类型是Long,但BillsKey中的id是int,两者类型不一致,JPA无法正确映射实例化主键类。 - 复合主键字段类型错误:
BillsKey中直接使用Suppliers实体类作为主键字段,不符合JPA@IdClass的要求——复合主键字段必须是基本类型、包装类或可序列化的简单类型,不能直接关联实体。
解决方案
1. 修改BillsKey类
将主键字段改为与Bills实体匹配的类型,并用关联实体的主键类型替换实体本身(假设Suppliers的主键是Long类型):
@NoArgsConstructor @AllArgsConstructor @Data public class BillsKey implements Serializable { // 用Suppliers的主键类型替换实体类 private Long supplierId; // 与Bills中的id类型保持一致,改为Long private Long id; }
2. 修改Bills实体类
调整@Id字段与BillsKey对应,将关联实体的注解与主键字段分离:
@Data @Table(schema = "PharmaPal", name = "Bills") @Entity @Builder @NoArgsConstructor @AllArgsConstructor @IdClass(BillsKey.class) public class Bills { @Id private Long id; // 作为复合主键的一部分,对应BillsKey中的supplierId @Id @Column(name = "supplier") private Long supplierId; // 关联Suppliers实体,无需添加@Id,设置insertable和updatable为false避免重复操作 @ManyToOne @JoinColumn(name = "supplier", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "fk_supplier")) private Suppliers supplier; @Temporal(TemporalType.DATE) private LocalDate billDate; private double total; @Temporal(TemporalType.DATE) private LocalDate dueDate; private String State; @OneToMany(mappedBy = "bills", cascade = CascadeType.ALL) private Set<StockedProducts> stockedProducts; }
说明
- JPA的
@IdClass要求主键类的字段必须和实体类中所有@Id标注的字段名称、类型完全一致,否则无法正确实例化主键类。 - 复合主键不能直接使用实体类型,需通过实体的主键字段关联,避免JSON序列化和JPA映射时出现实例化问题。
内容的提问来源于stack exchange,提问作者user21749778
相关产品推荐
相关产品推荐

