Как статически сплести объекты JPA с использованием EclipseLink, когда их нет persistence.xml поскольку объектами управляет Spring

#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.