测试配置下如何让Hibernate扫描主应用中的实体类?
我正在用JUnit为公司应用编写单元测试,应用通过JPA EntityManager接口使用Hibernate。测试时配置Hibernate Session注入遇到问题:Hibernate似乎未扫描到正确的实体类包。
我通过以下方式获取Session:
public static EntityManager getEntityManager() { if (sessionFactory == null) { final StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .configure() // 从hibernate.cfg.xml加载配置 .build(); try { sessionFactory = new MetadataSources(registry ).buildMetadata().buildSessionFactory(); } catch (Exception e) { StandardServiceRegistryBuilder.destroy( registry ); } } return sessionFactory.openSession(); }
我在hibernate.cfg.xml中定义了packagesToScan属性:
<property name="packagesToScan">com.[my company].model</property>
当调用业务方法执行如下HQL查询时:
entityManager.createQuery("Select u from User u")
出现报错:org.hibernate.hql.internal.ast.QuerySyntaxException: [my entity] is not mapped...,我认为实体类未被扫描到,怀疑原因是实体类位于src/main/java/目录下,而Hibernate Session是在src/test/java/目录中创建和配置的。
我的问题:
- 我的分析是否正确?
- 如何让Hibernate扫描与Session不在同一目录下的实体类?
我曾找到相关解决方案,但没能理解并正确实现。
1. 你的分析不完全准确
实体类所在的src/main/java目录在测试阶段会被编译到target/classes,测试代码src/test/java编译到target/test-classes,只要包路径正确,Hibernate不会因为源码目录不同而扫描不到实体。真正的问题大概率是当前Session创建方式未正确触发包扫描:
MetadataSources.buildMetadata()默认不会自动处理hibernate.cfg.xml里的packagesToScan属性,这个属性更多是Spring整合Hibernate时的生效配置,原生Hibernate API需要显式指定扫描的包。
2. 解决方法:显式指定实体扫描路径
修改getEntityManager()方法,在构建MetadataSources后主动添加包扫描:
public static EntityManager getEntityManager() { if (sessionFactory == null) { final StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .configure() .build(); try { MetadataSources sources = new MetadataSources(registry); // 显式添加要扫描的实体包 sources.addPackage("com.[my company].model"); // 若实体数量少,也可直接添加单个实体类 // sources.addAnnotatedClass(User.class); sessionFactory = sources.buildMetadata().buildSessionFactory(); } catch (Exception e) { StandardServiceRegistryBuilder.destroy(registry); throw new RuntimeException("SessionFactory初始化失败", e); } } return sessionFactory.openSession(); }
额外验证点
- 确认实体类上标注了
@Entity注解,且包路径与配置的com.[my company].model完全一致 - 检查测试类的classpath是否包含
src/main/java编译后的class文件(Maven/Gradle默认会包含,除非修改了编译配置) - 若为多模块项目,确保实体模块已被测试模块依赖,且依赖范围为
test或compile
内容的提问来源于stack exchange,提问作者Supetorus

