I found 2 possibilities without changing classloader/using other Maven plugins/profiles/copy-overwrite files.
TL;DR: check provider name.
At first I started to construct the entityManagerFactory programmatically, like here: create entity manager programmatically without persistence file.
So I did sth very similar:
@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;
}
}
But then, I found it still return null
. Why?
Then I found that when I use com.hibernate.ejb.HibernatePersistence
class, the provider should not be com.hibernate.jpa.HibernatePersistenceProvider
, but com.hibernate.ejb.HibernatePersistence
. The class HibernatePersistenceProvider
is not even found with IDEA "Open Class", even when it is in the main persistence.xml.
In Ejb3Configuration.class
I found:
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 {
So I went back to the first solution of persistence.xml
, and change provider name, and now it works. It seems that even the provider in main is jpa.xxx
, in tests it is not.
So, in summary, 3 things to check:
- turn on
-X
in Maven to check if maven-resources-plugin
really copied your src/test/resources/META-INF/persistence.xml
into target/test-classes
(I think this never fails)
- check if
hibernate-entitymanager
is in your classpath(you can check with mvn dependency:tree -Dincludes=org.hibernate:hibernate-entitymanager
.
- check provider's name, most important one. Should be
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>
...