当我创建复合持久性单元并尝试使用标准 API 时,我收到以下异常消息:
java.lang.IllegalArgumentException: No [EntityType] was found for the key class [nl.example.application.datalayer.entity.db.EntityA] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class>nl.example.application.datalayer.entity.db.EntityA</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
如果我执行 jpql 查询,我会得到我期望的结果。出于某种原因,元模型保持为空,如 server.log 中的警告所示:
The collection of metamodel [EntityType] types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units. Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element. The lookup on [class nl.example.application.datalayer.entity.db.EntityA] will return null.
我已经创建了我的应用程序的精简版本来显示问题,可以在这里找到。当我使用标准 API 时,数据层(包含复合持久性单元)的单元测试确实给出了正确的结果,请参阅上述项目中的 CompositeDAOTest。
示例项目的结构如下:
Example
|--- datalayer_project)
| |--- datalayer_parent
| | |--- pom.xml
| |
| |--- entity (some jar with entities)
| | |--- src
| | | |---main
| | | |--- java
| | | |--- resources
| | | |--- META-INF/persistence.xml
| | |--- pom.xml
| |
| |--- datalayer (the composite persistence unit to be used by the application)
| | |--- src
| | | |---main
| | | |--- java
| | | |--- resources
| | | |--- META-INF/persistence.xml
| | |--- build-jar-with-dependencies.xml (maven-assembly-plugin descriptor to build jar with all entites and their metamodel classes)
| | |--- pom.xml
| |--- pom.xml
|
|--- application (this is the example application which will be deployed)
| |--- src
| | |--- <source code>
| |--- pom.xml
|
|--- pom.xml
|--- setupServer.sh (script to create GlassFish/Payara domain)
实体 jar 的 persistence.xml 定义为
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="examplePU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/DataSource</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="eclipselink.composite-unit.member" value="true"/>
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.target-database" value="PostgreSQL"/>
<property name="eclipselink.deploy-on-startup" value="true" />
</properties>
</persistence-unit>
复合持久性单元(数据层)通过:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="CompositePu" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jar-file>entity-${project.version}.jar</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.composite-unit" value="true" />
<property name="eclipselink.logging.parameters" value="true" />
<property name="eclipselink.deploy-on-startup" value="true" />
</properties>
</persistence-unit>
</persistence>
该项目的主要可部署项目是一个战争,其中包括一个包含复合持久性单元和实体及其元模型类的胖 jar。创建此应用程序的 pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>nl.example.application</groupId>
<artifactId>application_project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>example</artifactId>
<packaging>war</packaging>
<name>example</name>
<dependencies>
<dependency>
<groupId>nl.example.application.datalayer</groupId>
<artifactId>datalayer</artifactId>
<version>${project.version}</version>
<classifier>jar-with-dependencies</classifier>
</dependency>
<dependency>
<groupId>de.danielbechler</groupId>
<artifactId>java-object-diff</artifactId>
<version>0.94</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>6.0</version>
</dependency>
<dependency>
<groupId>org.primefaces.themes</groupId>
<artifactId>all-themes</artifactId>
<version>1.0.10</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.25.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-core</artifactId>
<version>2.4.3.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.4.3.Final</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>example</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<classpathPrefix>example/WEB-INF/lib</classpathPrefix>
</manifest>
<manifestEntries>
<git-SHA-1>${buildNumber}</git-SHA-1>
</manifestEntries>
</archive>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<webResource>
<directory>${basedir}/src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>index.xhtml</include>
</includes>
</webResource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/business/util/control/Settings**</exclude>
<exclude>**/*_*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<scm>
<connection>scm:git:git@github.com:JCGreiner/JPACompositeAndMetaModel.git</connection>
<tag>HEAD</tag>
</scm>
</project>
为了轻松演示该问题,我在应用程序中创建了 3 个 REST 端点(存储实体、findEntityNative(应该是 findEntityJPQL)和 findEntityCriteria),这些端点使用 swagger 进行了记录,因此它们可以轻松执行。
使用项目的步骤(也可以在项目 wiki 上找到):
- 克隆,或下载存储库
- 运行 mvn 干净安装
- 在 postgres 中创建数据库用户: user: example password: example databasename: example 登录角色应该有足够的权限来创建和修改表;为了方便起见,我使用了超级用户
- 设置 GlassFish/Payara 域:使用 3 个参数在项目的根目录中运行 setupServer.sh 脚本:GlassFish/Payara 的路径 b. 域名,例如示例 c。端口库,例如 8000
- 创建域后,转到管理控制台(例如 localhost:8048)并部署应用程序。战争位于 /nl/example/application/example/1.0.0-SNAPSHOT/example-1.0.0-SNAPSHOT
- 运行 DDLGenerateIT 测试以生成数据库表
- 您现在可以通过访问http://localhost:8080/example/api-docs/index.html的默认部分下的 swagger 文档来测试应用程序,您将看到 3 REST 端点,并且可以轻松地对其进行测试。
摘要 (tldr):应用程序找不到复合持久性单元的元模型,即使 jpql 查询工作得很好,为什么?
尝试过,但没有解决方案:
1. 使用来自休眠的处理器生成元模型,如本主题中所建议
2. 由于使用了不同的类加载器,我尝试对 CompositeDAO 进行以下更改:
@PersistenceContext(unitName = "CompositePu")
protected EntityManager em;
我替换为:
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct
public void initialize() {
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("eclipselink.classloader", this.getClass().getClassLoader());
hashMap.put("eclipselink.composite-unit", "true");
hashMap.put("eclipselink.deploy-on-startup", "true");
em = Persistence.createEntityManagerFactory("CompositePu", hashMap).createEntityManager();
if (metamodel.getManagedTypes().isEmpty()) {
logger.log(Level.WARNING, "meta model is empty");
}
不幸的是,元模型仍然是空的,触发了上面的日志行。
- 这个关于 JPA 2.0的主题建议以语法方式将类描述符添加到元模型中。我创建了一个快速实现,但可惜没有成功(我创建的类描述符不完整)。然而,这可能是解决这个问题的最有希望的方法。
也很有用:
1.在运行时动态添加实体类