Hibernate 6.6含泛型复合@Id分散在@MappedSuperclass时启动失败
expecting IdClass mapping异常问题分析 更新记录
- 2025/05/12:排查后确认问题并非泛型标识符导致,而是复合键字段分散在不同类中的场景触发,该问题已在Hibernate官方BUG库中记录为HHH-19076并完成复现。
- 2025/08/01:HHH-19076已修复显式标识符的场景,但泛型标识符相关的问题仍未解决,已提交新BUG记录HHH-19706跟进。
问题详情
将org.springframework.boot:spring-boot-starter-parent从3.3.4升级至3.4.0(对应Hibernate从6.5.3.Final升级到6.6.2.Final)后,继承自@MappedSuperclass的实体类抛出java.lang.IllegalArgumentException: expecting IdClass mapping异常。
相关代码
父类(带泛型的映射超类):
import jakarta.persistence.Column; import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; import org.springframework.lang.Nullable; import java.io.Serializable; // ... 其他导入 @MappedSuperclass public abstract class Parent<K extends Serializable & Comparable<K>, C extends Parent<K, C>> { protected static final String LEADER_ID_COLUMN = "LEADER_ID"; @Id @Column(name = LEADER_ID_COLUMN, nullable = false, updatable = false) @Nullable private K leaderId; // ... 其他字段 @Nullable public K getLeaderId() { return leaderId; } public C setLeaderId(K entityId) { this.leaderId = entityId; return itself(); } // ... getter/setter/equals/hashCode/toString protected abstract C itself(); }
子类(触发异常的实体类):
import jakarta.persistence.Entity; import org.springframework.lang.Nullable; // ... 其他导入 @Entity public class Child extends Parent<Long, Child> { // ... 字段/getter/setter @Override protected Child itself() { return this; } // ... equals/hashCode/toString }
异常触发流程
当应用在Child实体中调用org.hibernate.persister.entity.AbstractEntityPersister.findAttributeMapping(String name)查找leaderId时,declaredAttributeMappings包含父类和子类的所有字段但不包含leaderId,且superMappingType为null,返回结果为null。这导致org.hibernate.metamodel.internal.AttributeFactory.resolveEntityMember调用resolveVirtualIdentifierMember,但此时identifierMapping.getNature()为SIMPLE而非要求的VIRTUAL,最终抛出上述异常。
已验证Hibernate 6.6.3.Final和6.6.4.Final版本均存在该问题。
结论
该问题并非代码违反了Hibernate新版本的更严格要求,而是Hibernate 6.6.x版本的BUG导致:
- 复合键分散在不同类中的场景已通过HHH-19076修复,但泛型标识符场景仍未解决;
- 泛型标识符相关的问题已提交HHH-19706,需等待官方后续版本修复。
内容的提问来源于stack exchange,提问作者Yury Shafran

