对于复合持久性单元

时间:2017-05-18 10:54:19

标签: jpa glassfish eclipselink payara

当我创建复合持久性单元并尝试使用条件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中的Warning所示:

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.

我创建了一个应用程序的精简版本来显示问题,可以找到here。 当我使用条件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>

复合持久性单元(datalayer)的那个:

<?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 here上找到):

  1. 克隆或下载存储库
  2. 运行mvn clean install
  3. 在postgres中创建数据库用户:  用户:示例  密码:示例  databasename:example  login角色应具有足够的权限来创建和修改表;为方便起见,我使用超级用户
  4. 设置GlassFish / Payara域名: 使用3个参数运行项目根目录中的setupServer.sh脚本:a。 GlassFish / Payara的路径b。域名,例如例子c。 portbase,例如8000
  5. 创建域后,转到管理控制台(例如localhost:8048)并部署应用程序。战争位于/nl/example/application/example/1.0.0-SNAPSHOT/example-1.0.0-SNAPSHOT
  6. 运行DDLGenerateIT测试以生成数据库表
  7. 您现在可以通过转到http://localhost:8080/example/api-docs/index.html处的swagger文档来测试应用程序,在默认部分下您将看到3 REST端点,并且可以轻松地测试它们。
  8. 摘要(tldr):应用程序无法找到复合持久性单元的元模型,即使jpql查询工作得很好,为什么呢?

    试过了,但是没有解决方案:
     1.使用来自hibernate的处理器生成元模型,如this主题中所述   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");
    }
    

    不幸的是,元模型仍然是空的,上面的日志行被触发。

    1. topic about JPA 2.0建议以编程方式将类描述符添加到元模型中。我已经创建了一个快速实现但是没有成功(我创建的类描述符并不完整)。然而,这可能是解决此问题的最有前途的方法。
    2. 也很有用:
        1. adding-entity-classes-dynamically-at-runtime

0 个答案:

没有答案