[英]Datanucleus, JDO and executable jar - how to do it?
我正在為嵌入式 H2 數據庫開發一個帶有 Datanucleus 和 JDO 的桌面應用程序。 當我從 Eclipse 運行它時一切正常,但是當我嘗試從中生成可執行文件 jar 時它停止工作。 我收到以下錯誤:
org.datanucleus.exceptions.NucleusUserException:已指定持久性進程使用名稱為“jdo”的 ClassLoaderResolver,但 DataNucleus 插件機制尚未找到它。 請檢查您的 CLASSPATH 和插件規范。
當然,這表明我沒有正確配置某些東西——我錯過了什么? 如果我遺漏了一些大的東西,它根本就不會工作,所以我假設它是一個有缺陷的可執行文件 jar。我在其他應用程序中看到過這個錯誤,比如 JPOX,它已被修復,但沒有給出任何解決方案。
整個錯誤堆棧跟蹤:
Exception in thread "main" javax.jdo.JDOFatalInternalException: Unexpected exception caught.
at javax.jdo.JDOHelper.invokeGetPersistenceManagerFactoryOnImplementation(JDOHelper.java:1193)
at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:808)
at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:701)
at db.PersistenceManagerFilter.init(PersistenceManagerFilter.java:44)
at Main.main(Main.java:26)
NestedThrowablesStackTrace:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at javax.jdo.JDOHelper$16.run(JDOHelper.java:1965)
at java.security.AccessController.doPrivileged(Native Method)
at javax.jdo.JDOHelper.invoke(JDOHelper.java:1960)
at javax.jdo.JDOHelper.invokeGetPersistenceManagerFactoryOnImplementation(JDOHelper.java:1166)
at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:808)
at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:701)
at db.PersistenceManagerFilter.init(PersistenceManagerFilter.java:44)
at Main.main(Main.java:26)
Caused by: org.datanucleus.exceptions.NucleusUserException: Persistence process has been specified to use a ClassLoaderResolver of name "jdo" yet this has not been found by the DataNucleus plugin mechanism. Please check your CLASSPATH and plugin specification.
at org.datanucleus.NucleusContext.<init>(NucleusContext.java:233)
at org.datanucleus.NucleusContext.<init>(NucleusContext.java:196)
at org.datanucleus.NucleusContext.<init>(NucleusContext.java:174)
at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.<init>(JDOPersistenceManagerFactory.java:364)
at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.createPersistenceManagerFactory(JDOPersistenceManagerFactory.java:294)
at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.getPersistenceManagerFactory(JDOPersistenceManagerFactory.java:195)
... 12 more
它指向的行是 PersistenceManagerFilter init 方法:
pmf = JDOHelper.getPersistenceManagerFactory(getProperties());
屬性文件如下所示:
javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.api.jdo.JDOPersistenceManagerFactory
datanucleus.ConnectionDriverName=org.h2.Driver
datanucleus.ConnectionURL=jdbc:h2:datanucleus
datanucleus.ConnectionUserName=sa
datanucleus.ConnectionPassword=
我擁有來自 maven 的所有依賴項,目標是使用依賴項進行部署。 依賴關系如 datanucleus 頁面http://www.datanucleus.org/products/datanucleus/jdo/maven.html所述
有任何想法嗎?
DataNucleus jars 都啟用了 OSGi,並使用插件機制來識別功能,因此包含plugin.xml和META-INF/MANIFEST.MF文件。 這些需要位於與原始 DN jars(來自 jar 的根目錄)中相同的位置。 如果您解壓然后重新打包它們,您將需要合並來自 DN jars 的任何 plugin.xml 和 META-INF/MANIFEST.MF ...所有信息,而不僅僅是其中的一部分。
添加到 DataNucleus 答案。
為了達到你需要的東西,你應該使用maven-dependency-plugin
並將以下內容添加到您的 pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/jars</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
然后依賴項將位於target/jars目錄中。
要執行您的應用程序,您可以使用命令:
Windows:
java -cp "yourFile.jar;jars/*" package.className
Linux:
java -cp "yourFile.jar:jars/*" package.className
注意:不要使用 jars/*.jar,這將不起作用
為了在需要單個 jar 的 Apache Storm 拓撲中使用 DataNucleus 4.x,我不得不進行兩次 hack 以保持其 PluginRegistry 工作正常。 問題是 DataNucleus 核心會嘗試將模塊作為 OSGi 包加載,即使它沒有在 OSGi 容器中運行。 只要不合並 jars 就可以正常工作(我不希望合並我的依賴項,但這對我來說不是一個選項)。
首先,我將所有 plugin.xml 文件合並到 datanucleus-core plugin.xml 中。 訣竅是擴展點 id 是相對於它們父插件的 id 的。 因此,如果您使用的任何模塊定義了新的擴展點,例如 datanucleus-rdbms,您必須重寫 id,以便它們相對於它們的新父插件。
其次,我將以下條目添加到我們的 jar 的 MANIFEST.MF 中:
Premain-Class: org.datanucleus.enhancer.DataNucleusClassFileTransformer
Bundle-SymbolicName: org.datanucleus;singleton:=true
這個解決方案並不理想,因為我們的應用程序本質上是假裝是 DataNucleus 核心 OSGi 包。 然而,這就是我在休息幾天后把頭撞在桌子上的結果。
可能提供不同的 PluginRegistry 實現,但我沒有研究過這個。
對於努力合並 datanucleus plugin.xml 文件的其他任何人,我使用以下代碼來提供幫助。 Pipe 來自 3 個單獨的 datanucleus plugin.xml 文件的內容使用此命令,這將告訴您哪里有明確需要合並的擴展:
cat plugin_core.xml plugin_rdbms.xml plugin_api.xml | grep -h "extension point" | tr -d "[:blank:]"| sort | uniq -d
更多詳細信息在單獨的帖子中。
基於現有答案(尤其是https://stackoverflow.com/a/27030103/1571826 ),使用 RDBMS 插件的 ID 手動覆蓋我的plugin.xml
一次。 為此,我遵循了這個答案: https://stackoverflow.com/a/37511856/1571826
將新plugin.xml
存儲為資源后,我按如下方式配置了maven-shade-plugin
:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<finalName>${project.artifactId}-shaded</finalName>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/DEPENDENCIES</exclude>
<exclude>META-INF/license/*</exclude>
<exclude>META-INF/LICENSE</exclude>
<exclude>META-INF/NOTICE</exclude>
</excludes>
</filter>
</filters>
<transformers>
<!--
Metastore dependencies require below highly specific merging solutions:
- https://github.com/apache/iceberg/issues/5946#issuecomment-1278674526
- https://stackoverflow.com/a/10106373/1571826
- https://stackoverflow.com/a/37511856/1571826
-->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>META-INF/MANIFEST</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>${mainClass}</Main-Class>
<Premain-Class>org.datanucleus.enhancer.DataNucleusClassFileTransformer</Premain-Class>
<Bundle-SymbolicName>org.datanucleus;singleton:=true</Bundle-SymbolicName>
</manifestEntries>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>plugin.xml</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>plugin.xml</resource>
<file>src/main/resources/plugin.xml</file>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>reference.conf</resource>
</transformer>
</transformers>
</configuration>
</plugin>
</plugins>
</build>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.