没有 persistence.xml 时如何使用 EclipseLink 静态编织 JPA 实体,因为实体由 Spring 管理

How to statically weave JPA entities using EclipseLink when there is no persistence.xml as the entities are managed by Spring

我有一个基于 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。

有什么方法可以在基于 Spring 的 JPA 项目中静态编织 JPA 实体?

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

我承认,我没有完全理解你说的编织是什么意思。如果您需要动态创建提供 JPA-Entitymanagers 的 PersistenceUnits,并且这些单元是否应该能够创建 Db-Schema(例如在 H2 中)并根据您提供的 类 动态管理实体,我的回答可能会有所帮助在运行时。

我稍后提到的代码示例不适用于 Spring 中的 JPA,但适用于 Weld。我认为您问题的答案与 EntityManager 的创建方式以及创建 EntityManager 的 PersistenceUnit 所管理的内容 类 有关。这两者之间没有区别。除了使用 EntityManagerFactory 作为 CDI-Producer,您还可以使用老式的应用程序上下文自动装配或注册它。因此,我认为您的问题的答案在于以下官方来源

PersistenceProviderResolverHolderPersistenceProvider#createEntityManagerFactory(getPersistenceUnitName(), 属性) properties 是 persistence.xml 的替代品,其中可以注册 SEPersistenceUnitInfo 对象。

开始看:PersistenceProviderResolverHolder 后来:PersistenceProvider

或者您可以尝试了解我的代码(见下文)是如何做到这一点的。但我不得不承认,我对那个软件的这部分不是很自豪,抱歉。

那些 类 和对象被我用来创建一个模块,该模块可以模拟部署在服务器上的 JPA-WAR-文件。 为此,它会扫描一些 类 并识别实体。 稍后在测试代码中,所谓的 PersistenceFactory 创建 EntityManager 和数据源。如果使用 eclipselink,该工厂会将这些 类 编织在一起。你不需要 persistence.xml。在那里工作可能有助于回答您的问题。

如果您查看: ioc-unit-ejb:TestPersistencefactory 搜索 SEPersistenceUnitInfo 的创建。该接口由 类 列表提供,它 returns 为

@Override
public List<String> getManagedClassNames() {
    return TestPersistenceFactory.this.getManagedClassNames();
}

此对象用于在 PersistenceProvider 的帮助下创建 Persistencefactory。只要 eclipselink 在类路径中可用,就可以发现这一点。

代码不容易理解,因为它允许 Hibernate 或 Eclipselink 用于 JPA,这取决于类路径中 jars 的可用性。

根据 org.eclipse.persistence.tools.weaving.jpa.StaticWeave 文档,它需要 persistence.xml 到位才能生成静态编织源。

Usage:
StaticWeave [options] source target

Options:
-classpath Set the user class path, use ";" as the delimiter in Window system and ":" in Unix system.

-log The path of log file, the standard output will be the default.

-loglevel Specify a literal value for eclipselink log level(OFF,SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST). The default value is OFF.

-persistenceinfo The path contains META-INF/persistence.xml. This is ONLY required when the source does not include it. The classpath must contain all the classes necessary in order to perform weaving.

我 运行 使用 eclipselink maven 插件 maven 构建,它可以在没有 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);
    }

完整的源码是here

我相信您可以在 gradle 构建中采用相同的方法。

晚会有点晚了,但这绝对有可能 Gradle。

要完成这项工作,需要执行 3 个步骤:

  • 将 persistence.xml 文件复制到 类
  • 旁边的源文件夹中
  • 织布
  • 从 类 源文件夹中删除 persistence.xml 文件以避免类路径上的重复 persistence.xml 冲突

此外,为了不破坏 Gradle 的 up-to-date 检查,将编织过程挂接到 compileJava 任务的最后一步非常重要,否则 Gradle 将重新编译所有内容一直这样,开发的时候会很不方便。

更详细的解释可以看我的文章:EclipseLink static weaving with Gradle.