我发现了 2 种可能性,而无需更改类加载器/使用其他 Maven 插件/配置文件/复制覆盖文件。
TL;DR:检查提供者名称。
起初,我开始以编程方式构建 entityManagerFactory,如下所示:create entity manager programmatically without persistence file。
所以我做了非常相似的事情:
@BeforeClass
public static void prepare() {
Map<String, Object> configOverrides = new HashMap<>();
configOverrides.put("hibernate.connection.driver_class", "org.h2.Driver");
configOverrides.put("hibernate.connection.url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
configOverrides.put("hibernate.connection.username", "sa");
configOverrides.put("hibernate.connection.password", "sa");
configOverrides.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
configOverrides.put("hibernate.show_sql", "true");
configOverrides.put("hibernate.hbm2ddl.auto", "validate");
factory = new HibernatePersistence().createContainerEntityManagerFactory(
new CustomPersistenceUnitInfo(), configOverrides
);
//factory = Persistence.createEntityManagerFactory("test");
assertNotNull(factory);
}
...
private static class CustomPersistenceUnitInfo implements PersistenceUnitInfo {
@Override
public String getPersistenceUnitName() {
return "test";
}
@Override
public String getPersistenceProviderClassName() {
return "org.hibernate.jpa.HibernatePersistenceProvider";
// <------------note here: this is wrong!
}
@Override
public PersistenceUnitTransactionType getTransactionType() {
return PersistenceUnitTransactionType.RESOURCE_LOCAL;
}
@Override
public DataSource getJtaDataSource() {
return null;
}
@Override
public DataSource getNonJtaDataSource() {
return null;
}
@Override
public List<String> getMappingFileNames() {
return Collections.emptyList();
}
@Override
public List<URL> getJarFileUrls() {
try {
return Collections.list(this.getClass()
.getClassLoader()
.getResources(""));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public URL getPersistenceUnitRootUrl() {
return null;
}
@Override
public List<String> getManagedClassNames() {
return Arrays.asList(
"com.app.Entity1",
"com.app.Entity2"
);
}
@Override
public boolean excludeUnlistedClasses() {
return true;
}
@Override
public SharedCacheMode getSharedCacheMode() {
return null;
}
@Override
public ValidationMode getValidationMode() {
return null;
}
@Override
public Properties getProperties() {
return null;
}
@Override
public String getPersistenceXMLSchemaVersion() {
return null;
}
@Override
public ClassLoader getClassLoader() {
return null;
}
@Override
public void addTransformer(final ClassTransformer classTransformer) {
}
@Override
public ClassLoader getNewTempClassLoader() {
return null;
}
}
但是后来,我发现它仍然返回null
。为什么?
然后我发现我在使用com.hibernate.ejb.HibernatePersistence
class的时候,provider应该不是com.hibernate.jpa.HibernatePersistenceProvider
,而是com.hibernate.ejb.HibernatePersistence
。HibernatePersistenceProvider
即使在主persistence.xml中,IDEA“Open Class”也找不到该类。
在Ejb3Configuration.class
我发现:
integration = integration != null ? Collections.unmodifiableMap(integration) : CollectionHelper.EMPTY_MAP;
String provider = (String)integration.get("javax.persistence.provider");
if (provider == null) {
provider = info.getPersistenceProviderClassName();
}
if (provider != null && !provider.trim().startsWith(IMPLEMENTATION_NAME)) { // private static final String IMPLEMENTATION_NAME = HibernatePersistence.class.getName(); which, is, "com.hibernate.ejb.HibernatePersistence"
LOG.requiredDifferentProvider(provider);
return null;
} else {
所以我回到了第一个解决方案persistence.xml
,并更改了提供者名称,现在它可以工作了。似乎即使 main 中的提供者是jpa.xxx
,在测试中也不是。
因此,总而言之,要检查 3 件事:
- 在 Maven 中打开
-X
以检查是否maven-resources-plugin
真的复制了你的src/test/resources/META-INF/persistence.xml
(target/test-classes
我认为这永远不会失败)
- 检查是否
hibernate-entitymanager
在您的类路径中(您可以使用mvn dependency:tree -Dincludes=org.hibernate:hibernate-entitymanager
.
- 检查提供商的名称,最重要的一个。应该是
org.hibernate.ejb.HibernatePersistence
。
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.app.model.Company</class>
...