我发现了 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.HibernatePersistenceclass的时候,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>
        ...