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

添加@Builder至AppUser实体触发Hibernate UnknownEntityTypeException的原因

问题分析:Hibernate UnknownEntityTypeException与Lombok @Builder的冲突

问题场景

我在实现功能时采用了一种实体映射方案,向Company发送POST请求时抛出异常:org.hibernate.UnknownEntityTypeException: Unable to locate entity descriptor。但把AppUser实体类上的@Builder注解移除后,异常就不再出现,想搞清楚为什么加注解会出问题,去掉就正常。

异常堆栈信息

org.hibernate.UnknownEntityTypeException: Unable to locate entity descriptor: com.solanke.spring6jobboardrest.domains.AppUser$AppUserBuilder
    at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.getEntityDescriptor(MappingMetamodelImpl.java:435) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.internal.SessionImpl.requireEntityPersister(SessionImpl.java:2271) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.internal.SessionImpl.byId(SessionImpl.java:1173) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.internal.SessionImpl.getReference(SessionImpl.java:2507) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360) ~[spring-orm-6.0.9.jar:6.0.9]
    at jdk.proxy2/jdk.proxy2.$Proxy129.getReference(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-6.0.9.jar:6.0.9]
    at jdk.proxy2/jdk.proxy2.$Proxy129.getReference(Unknown Source) ~[na:na]
    at com.solanke.spring6jobboardrest.mappers.ReferenceMapper.map(ReferenceMapper.java:18) ~[classes/:na]
    at com.solanke.spring6jobboardrest.mappers.AppUserMapperImpl.toAppUser(AppUserMapperImpl.java:27) ~[classes/:na]
    at com.solanke.spring6jobboardrest.mappers.CompanyMapperImpl.companyDtoToCompany(CompanyMapperImpl.java:28) ~[classes/:na]
    at com.solanke.spring6jobboardrest.services.CompanyServiceImpl.saveNewCompany(CompanyServiceImpl.java:29) ~[classes/:na]
    at com.solanke.spring6jobboardrest.controllers.CompanyController.createCompany(CompanyController.java:34) ~[classes/:na]

相关代码实现

ReferenceMapper类

@Component
public class ReferenceMapper {

    @PersistenceContext
    private EntityManager entityManager;

    @ObjectFactory
    public <T> T map(@NonNull final Long id, @TargetType Class<T> type) {
        return entityManager.getReference(type, id);
    }
}

自动生成的AppUserMapperImpl代码

@Override
public AppUser toAppUser(Long id) {
    if ( id == null ) {
        return null;
    }

    AppUser.AppUserBuilder appUser = referenceMapper.map( id, AppUser.AppUserBuilder.class );

    appUser.id( id );

    return appUser.build();
}

自动生成的CompanyMapperImpl代码

@Override
public Company companyDtoToCompany(CompanyDto dto) {
    if ( dto == null ) {
        return null;
    }

    Company.CompanyBuilder company = Company.builder();

    company.adminProfile( appUserMapper.toAppUser( dto.getUserId() ) );
    company.id( dto.getId() );
    company.companyName( dto.getCompanyName() );
    company.description( dto.getDescription() );

    return company.build();
}

CompanyDto类代码

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CompanyDto {

    private Long id;

    @NotNull
    @NotBlank
    private String companyName;

    @NotNull
    @NotBlank
    private String description;

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Long userId;

}

原因解析

  1. Lombok @Builder的影响:当AppUser实体添加@Builder注解后,Lombok会自动生成一个内部静态构建器类AppUser$AppUserBuilder。
  2. MapStruct的生成逻辑:MapStruct在生成toAppUser方法时,会优先识别到实体类的Builder类,错误地将AppUser.AppUserBuilder.class作为目标类型传给referenceMapper.map()方法。
  3. Hibernate的要求:entityManager.getReference()方法要求传入的type必须是Hibernate管理的实体类,但AppUserBuilder只是一个构建器,不是被@Entity注解标记的实体,所以Hibernate找不到对应的实体描述符,抛出UnknownEntityTypeException。
  4. 移除@Builder后的变化:去掉@Builder注解后,MapStruct找不到对应的Builder类,就会直接以AppUser.class作为目标类型调用referenceMapper.map(),此时传入的是合法的实体类,Hibernate能正常识别并找到实体描述符,因此异常消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 14:36:00