Метамодель пустая для составной персистентной единицы
Когда я создаю составной модуль персистентности и пытаюсь использовать 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, я получу ожидаемые результаты. По какой-то причине метамодель остается пустой, как показано в Warning в 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)
Файл persistence.xml jar объекта определяется
<?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>
Основной развертываемый проект - война, которая включает в себя толстый кувшин, содержащий составную единицу персистентности и сущности с их классами метамодели. Пом, который создает это приложение:
<?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 (store entity, findEntityNative (должно было быть findEntityJPQL) и findEntityCriteria) в приложении, которые задокументированы с использованием swagger, чтобы их можно было легко выполнить.
Шаги для использования проекта (также можно найти в вики проекта здесь):
- Клонировать или скачать репозиторий
- Запустите mvn clean install
- Создайте пользователя базы данных в postgres: пользователь: пример пароля: пример имени базы данных: пример, роль входа должна иметь достаточные права для создания и изменения таблиц; Я использовал суперпользователя для удобства
- Настройка домена GlassFish/Payara: Запустите сценарий setupServer.sh в корневом каталоге проекта с 3 аргументами: a. путь к GlassFish/Payara б. доменное имя, например, пример c. база портов, например 8000
- После создания домена перейдите в консоль администратора (например, localhost:8048) и разверните приложение. война находится в /nl/example/application/example/1.0.0-SNAPSHOT/example-1.0.0-SNAPSHOT
- Запустите тест DDLGenerateIT, чтобы сгенерировать таблицы базы данных.
- Теперь вы можете протестировать приложение, перейдя к документации по swagger, которая находится по адресу http://localhost:8080/example/api-docs/index.html здесь, в разделе по умолчанию, вы увидите конечную точку 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. добавление-сущность-классы-динамически во время выполнения