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

Spring Boot+Hibernate中嵌套Embeddable的ElementCollection保存报NPE

问题分析与解决建议

错误根源

Hibernate 在处理 @Embeddable 类型时,需要能够设置类的属性值,但你的 Specification 和 ValueOfSpec 类中所有字段都使用了 final 修饰符。由于 final 字段初始化后无法被重新赋值,Hibernate 无法为这些字段生成对应的 Setter 方法,导致 PropertyAccess.getSetter() 返回 null,最终抛出 NullPointerException。

解决方案

1. 修改嵌入类的 final 字段

将 Specification 和 ValueOfSpec 中的 final 字段改为非 final,并添加对应的 Setter 方法(Hibernate 可通过反射访问字段,但添加 Setter 更符合规范):

修改后的 Specification 类

@Embeddable
public class Specification implements Serializable {
  private String fieldName;
  private String fieldType;
  private boolean required;
  private boolean readOnly;

  public Specification() {
    this.fieldName = null;
    this.fieldType = null;
    this.required = false;
    this.readOnly = false;
  }

  public Specification(String fieldName, String fieldType, boolean required, boolean readOnly) {
    this.fieldName = fieldName;
    this.fieldType = fieldType;
    this.readOnly = readOnly;
    this.required = required;
  }

  // 保留原有 getter 方法
  public String getFieldName() {
    return fieldName;
  }

  public String getFieldType() {
    return fieldType;
  }

  public boolean isReadOnly() {
    return readOnly;
  }

  public boolean isRequired() {
    return required;
  }

  // 添加 Setter 方法
  public void setFieldName(String fieldName) {
    this.fieldName = fieldName;
  }

  public void setFieldType(String fieldType) {
    this.fieldType = fieldType;
  }

  public void setRequired(boolean required) {
    this.required = required;
  }

  public void setReadOnly(boolean readOnly) {
    this.readOnly = readOnly;
  }

  // 保留原有 equals、hashCode 方法
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Specification that)) return false;
    return isRequired() == that.isRequired() && isReadOnly() == that.isReadOnly()
        && Objects.equals(getFieldName(), that.getFieldName())
        && Objects.equals(getFieldType(), that.getFieldType());
  }

  @Override
  public int hashCode() {
    return Objects.hash(getFieldName(), getFieldType(), isRequired(), isReadOnly());
  }
}

修改后的 ValueOfSpec 类

@Embeddable
public class ValueOfSpec implements Serializable {
  private Specification specification;
  private String value;

  public ValueOfSpec(Specification specification, String value) {
    this.specification = specification;
    this.value = value;
  }

  public ValueOfSpec() {
    this.value = null;
    this.specification = null;
  }

  // 保留原有 getter 方法
  public Specification getSpecification() {
    return specification;
  }

  public String getValue() {
    return value;
  }

  // 添加 Setter 方法
  public void setSpecification(Specification specification) {
    this.specification = specification;
  }

  public void setValue(String value) {
    this.value = value;
  }

  // 保留原有其他方法
}

2. 额外检查

同时注意 Product 类中的 auditInformation 字段也是 final 修饰,如果该字段同样是需要 Hibernate 处理的嵌入类或实体属性,建议一并修改为非 final 并添加 Setter 方法,避免后续出现同类问题。

补充说明

如果希望保持类的不可变性,可以尝试给嵌入类添加 @Immutable 注解,但该注解会让 Hibernate 对该类实例只做读取操作,不执行更新逻辑。如果你的业务场景需要修改这些嵌入类的属性,去掉 final 修饰符是最直接有效的解决方案。

内容的提问来源于stack exchange,提问作者eynoc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:58:07