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

Spring Boot 3迁移报错:无法定位AbstractEntity的id属性

Spring Boot 2.5迁移至3.0 RC1后泛型限定引发Hibernate属性查找错误

问题现象

原本运行正常的Spring Boot 2.5应用迁移到3.0 RC1后,调用仓库方法translationRepository.findTranslationsByClassifierId(1L)时触发如下错误:

Caused by: java.lang.IllegalArgumentException: Unable to locate Attribute with the given name [id] on this ManagedType [com.example.demo.domain.AbstractEntity]
at org.hibernate.metamodel.model.domain.AbstractManagedType.checkNotNull(AbstractManagedType.java:281) ~[hibernate-core-6.1.4.Final.jar:6.1.4.Final]
...

经排查,该错误与泛型限定<T extends AbstractEntity & WithTranslationKey>直接相关——移除WithTranslationKey后错误消失。Spring Boot 2.5版本无此问题,疑问这是否属于Spring Boot 3的Bug。

简化代码示例

1. 抽象实体基类

@MappedSuperclass
@Data
@NoArgsConstructor
@AllArgsConstructor
public abstract class AbstractEntity {

    @Id
    @GeneratedValue
    private Long id;

}

2. 用户实体类

@Entity(name = "USERS")
@Data
@NoArgsConstructor
public class User extends AbstractEntity implements WithTranslationKey {

    private String name;

    @Override
    public String getTranslationKey() {
        return name;
    }

    @Builder
    User(Long id, String name) {
        super(id);
        this.name = name;
    }
}

3. 抽象翻译实体类

@MappedSuperclass
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public abstract class AbstractTranslationEntity<T extends AbstractEntity & WithTranslationKey> extends AbstractEntity {

    @JoinColumn(name = "CLASSIFIER_ID", nullable = false)
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private T classifier;

    @Column(name = "LOCALE_CODE", length = 15, nullable = false)
    private String localeCode;

    AbstractTranslationEntity(Long id, T classifier, String localeCode) {
        super(id);
        this.classifier = classifier;
        this.localeCode = localeCode;
    }
}

4. 用户翻译实体类

@Data
@NoArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "USER_TRANSLATION")
public class UserTranslation extends AbstractTranslationEntity<User> {

    private String translation;

    @Builder
    UserTranslation(Long id, User classifier, String localeCode, String translation) {
        super(id, classifier, localeCode);
        this.translation = translation;
    }
}

5. 仓库接口定义

@NoRepositoryBean
public interface AbstractTranslationRepository<C extends AbstractEntity & WithTranslationKey, T extends AbstractTranslationEntity<C>> extends CrudRepository<T, Long> {

    List<T> findTranslationsByClassifierId(Long classifierId);

}

public interface UserTranslationRepository extends AbstractTranslationRepository<User, UserTranslation> {
}

问题分析与解决方案

这并非Spring Boot 3本身的Bug,而是Hibernate 6.x(Spring Boot 3默认依赖版本)在处理带多重边界的泛型类型时,元模型解析逻辑发生变化导致的问题。Hibernate 5.x(Spring Boot 2.5默认版本)对泛型边界解析更宽松,能正确识别AbstractEntity上的id属性;但Hibernate 6.x在处理T extends AbstractEntity & WithTranslationKey这类多重边界时,可能优先将T解析为WithTranslationKey接口类型,进而找不到id属性。

可行的解决方案:

  • 明确属性路径:修改仓库方法签名,用下划线明确指定属性层级:
    List<T> findTranslationsByClassifier_Id(Long classifierId);
    
  • 手动编写JPQL:绕过Spring Data的方法名自动解析,直接定义查询语句:
    @Query("SELECT t FROM #{#entityName} t WHERE t.classifier.id = :classifierId")
    List<T> findTranslationsByClassifierId(@Param("classifierId") Long classifierId);
    
  • 调整泛型约束结构:如果业务允许,让WithTranslationKey接口继承AbstractEntity,或者拆分多重边界的泛型定义,避免同时使用类和接口作为泛型边界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:15:47