#spring #spring-data-jpa #eclipselink #compile-time-weaving
#spring #spring-data-jpa #eclipselink #переплетение во время компиляции
Вопрос:
У меня есть проект, основанный на Spring, поэтому диспетчер объектов настраивается программно, без необходимости persistence.xml файлы для перечисления всех объектов.
В настоящее время я использую плетение во время загрузки, но пытаюсь заставить статическое плетение работать с использованием Eclipselink и Gradle. Я хочу повторить то, что выполняется плагином maven eclipselink:
https://github.com/ethlo/eclipselink-maven-plugin
У меня настроен следующий gradle (обратите внимание, что это Kotlin DSL, а не groovy):
task<JavaExec>("performJPAWeaving") {
val compileJava: JavaCompile = tasks.getByName("compileJava") as JavaCompile
dependsOn(compileJava)
val destinationDir = compileJava.destinationDir
println("Statically weaving classes in $destinationDir")
inputs.dir(destinationDir)
outputs.dir(destinationDir)
main = "org.eclipse.persistence.tools.weaving.jpa.StaticWeave"
args = listOf("-persistenceinfo", "src/main/resources", destinationDir.getAbsolutePath(), destinationDir.getAbsolutePath())
classpath = configurations.getByName("compile")
}
Когда я пытаюсь запустить задачу, задачи переплетения завершаются неудачей, поскольку она ищет несуществующий persistence.xml .
Есть ли какой-либо способ статически сплести объекты JPA в проекте JPA на основе Spring?
Exception Description: An exception was thrown while processing persistence.xml from URL: file:/home/blabla/trunk/my-module/src/main/resources/
Internal Exception: java.net.MalformedURLException
at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionProcessingPersistenceXML(PersistenceUnitLoadingException.java:117)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processPersistenceXML(PersistenceUnitProcessor.java:579)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processPersistenceArchive(PersistenceUnitProcessor.java:536)
... 6 more
Caused by: java.net.MalformedURLException
at java.net.URL.<init>(URL.java:627)
at java.net.URL.<init>(URL.java:490)
at java.net.URL.<init>(URL.java:439)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:620)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:148)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:806)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processPersistenceXML(PersistenceUnitProcessor.java:577)
... 7 more
Caused by: java.lang.NullPointerException
at java.net.URL.<init>(URL.java:532)
... 17 more
Ответ №1:
Согласно org.eclipse.persistence.tools.weaving.jpa.StaticWeave
документации, для создания статических источников переплетения требуется persistence.xml
наличие.
Использование:
StaticWeave [параметры] исходный целевойОпции:
-classpath Задайте путь к пользовательскому классу, используйте «;» в качестве разделителя в системе Window и «:» в системе Unix.-запишите путь к файлу журнала, стандартный вывод будет по умолчанию.
-loglevel Укажите буквальное значение для уровня журнала eclipselink(OFF, SERIOUS,WARNING,INFO, CONFIG, FINE, FINER,FINEST). Значение по умолчанию выключено.
-persistenceinfo Путь содержит META-INF/persistence.xml . Это требуется только тогда, когда источник не включает его. Путь к классам должен содержать все классы, необходимые для выполнения переплетения.
Я запускаю сборку maven с использованием плагина maven eclipselink, он работает без persistence.xml
, как вы упомянули, потому что он генерирует persistence.xml
перед вызовом StaticWeave.class
, когда он не находится в CLASSPATH
, используя этот метод.
private void processPersistenceXml(ClassLoader classLoader, Set<String> entityClasses)
{
final File targetFile = new File(this.persistenceInfoLocation "/META-INF/persistence.xml");
getLog().info("persistence.xml location: " targetFile);
final String name = project.getArtifactId();
final Document doc = targetFile.exists() ? PersistenceXmlHelper.parseXml(targetFile) : PersistenceXmlHelper.createXml(name);
checkExisting(targetFile, classLoader, doc, entityClasses);
PersistenceXmlHelper.appendClasses(doc, entityClasses);
PersistenceXmlHelper.outputXml(doc, targetFile);
}
Полный исходный код находится здесь
Я полагаю, вы могли бы следовать тому же подходу в своей сборке gradle.
Ответ №2:
Немного поздно для вечеринки, но это определенно возможно с Gradle.
Для того, чтобы это сработало, нужно выполнить 3 шага:
- Скопируйте persistence.xml файл в исходную папку рядом с классами
- Выполните переплетение
- Удалите
persistence.xml
файл из папки classes source, чтобы избежать повторяющихсяpersistence.xml
конфликтов на пути к классу
Кроме того, очень важно подключить процесс переплетения к последнему шагу задачи compileJava, чтобы не нарушать проверку актуальности Gradle, иначе Gradle будет просто все время перекомпилировать, что может быть довольно неудобно при разработке.
Для более подробного объяснения ознакомьтесь с моей статьей об этом: Статическое переплетение EclipseLink с Gradle.
Комментарии:
1. Я не могу протестировать это решение, поскольку я перешел от компании, которая использовала Eclipselink, но это выглядит как лучшее решение, поэтому помечаю его как таковое.
Ответ №3:
Признаюсь, я не совсем понимаю, что вы подразумеваете под переплетением. Мой ответ может помочь, если вам нужно динамически создавать PersistenceUnits, которые предоставляют JPA-Entitymanagers, и если эти модули должны иметь возможность создавать Db-Schema (например, в H2) и динамически управлять объектами на основе классов, которые вы предоставляете во время выполнения.
Пример кода, который я упомяну позже, работает не с JPA в Spring, а в Weld. Я думаю, что ответ на ваш вопрос связан с тем, как создаются EntityManagers и какими классами управляет PersistenceUnit, который создает EntityManager. Между этими двумя нет разницы. Вместо использования EntityManagerFactory в качестве CDI-производителя вы можете автоматически подключить его или зарегистрировать, используя старомодный application-context. Поэтому я думаю, что ответ на ваш вопрос содержится в следующих официальных источниках:
PersistenceProviderResolverHolder и PersistenceProvider#createEntityManagerFactory(getPersistenceUnitName(), properties)
свойства являются заменой для persistence.xml , где может быть зарегистрирован SEPersistenceUnitInfo-объект.
Для начала посмотрите: PersistenceProviderResolverHolder Позже: PersistenceProvider
или вы можете попытаться понять, как мой код (см. Ниже) это делает. Но я должен признать, я не очень горжусь этой частью этого программного обеспечения, извините.
Эти классы и объекты используются мной для создания модуля, который позволяет моделировать развернутый сервером JPA-WAR-File. Для этого он сканирует некоторые классы и идентифицирует объекты. Позже в тестовом коде так называемый PersistenceFactory создает EntityManager и источники данных. Если используется eclipselink, эта фабрика объединяет эти классы вместе. Вам не нужно persistence.xml . Работа там может помочь ответить на ваш вопрос.
Если вы посмотрите на: ioc-unit-ejb:TestPersistencefactory, найдите создание SEPersistenceUnitInfo. Этот интерфейс был загружен списком классов, который он возвращает как
@Override
public List<String> getManagedClassNames() {
return TestPersistenceFactory.this.getManagedClassNames();
}
Этот объект используется для создания Persistencefactory с помощью PersistenceProvider. Это можно обнаружить, как только eclipselink станет доступен в classpath.
Понять код непросто, потому что он позволяет использовать для JPA как Hibernate, так и Eclipselink, что зависит от доступности jar в classpath.