添加@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; }
原因解析
- Lombok @Builder的影响:当
AppUser实体添加@Builder注解后,Lombok会自动生成一个内部静态构建器类AppUser$AppUserBuilder。 - MapStruct的生成逻辑:MapStruct在生成
toAppUser方法时,会优先识别到实体类的Builder类,错误地将AppUser.AppUserBuilder.class作为目标类型传给referenceMapper.map()方法。 - Hibernate的要求:
entityManager.getReference()方法要求传入的type必须是Hibernate管理的实体类,但AppUserBuilder只是一个构建器,不是被@Entity注解标记的实体,所以Hibernate找不到对应的实体描述符,抛出UnknownEntityTypeException。 - 移除@Builder后的变化:去掉
@Builder注解后,MapStruct找不到对应的Builder类,就会直接以AppUser.class作为目标类型调用referenceMapper.map(),此时传入的是合法的实体类,Hibernate能正常识别并找到实体描述符,因此异常消失。
内容的提问来源于stack exchange,提问作者solanke57
相关产品推荐
相关产品推荐

