You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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]

问题分析

  1. 类型不匹配:Bills实体中的id字段类型是Long,但BillsKey中的id是int,两者类型不一致,JPA无法正确映射实例化主键类。
  2. 复合主键字段类型错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:03:15