I am developing a desktop app with Datanucleus and JDO for embedded H2 database. It all works fine when I run it from Eclipse, but it stops working when I try to make executable jar out of it. I get a following error:
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.
Of course it shows that I have not configured something properly - what am I missing? If I was missing something big, it wouldn't work at all, so I am assuming it's a flawed executable jar. I have seen that error in other apps, like JPOX, where it was fixed, but without any solution given.
Whole error stacktrace:
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
The line it points to is PersistenceManagerFilter init method:
pmf = JDOHelper.getPersistenceManagerFactory(getProperties());
Properties file looks like that:
javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.api.jdo.JDOPersistenceManagerFactory
datanucleus.ConnectionDriverName=org.h2.Driver
datanucleus.ConnectionURL=jdbc:h2:datanucleus
datanucleus.ConnectionUserName=sa
datanucleus.ConnectionPassword=
I have all dependencies from maven, with a goal to deploy with dependencies. Dependencies are as stated on datanucleus page http://www.datanucleus.org/products/datanucleus/jdo/maven.html
Any ideas?
DataNucleus jars are all OSGi-enabled and use a plugin mechanism to identify capabilities, so contain plugin.xml and META-INF/MANIFEST.MF files. These need to be in the same locations as they are in the original DN jars (from the root of the jar). If you unpack and then rejar them up you will need to merge any plugin.xml and META-INF/MANIFEST.MF from the DN jars ... ALL of the information there not just some of it.
Adding to DataNucleus answer.
To acheave what you need you should use maven-dependency-plugin
and add following to your 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>
Then the dependencies will be in target/jars dir.
To execute your app you use command:
Windows:
java -cp "yourFile.jar;jars/*" package.className
Linux:
java -cp "yourFile.jar:jars/*" package.className
NOTE: do not use jars/*.jar, this will not work
In order to use DataNucleus 4.x in an Apache Storm topology which requires a single jar, I had to do two hacks in order to keep their PluginRegistry stuff working. The issue is that the DataNucleus core tries to load modules as OSGi bundles, even when it is not running in an OSGi container. This works fine as long as the jars are not merged (and I would prefer not to merge my dependencies, but this is not an option for me).
First, I merged all the plugin.xml files into the datanucleus-core plugin.xml. The trick is that extension-point ids are relative to their parent plugin's id. So if any of the modules your are using define new extension-points, e.g. datanucleus-rdbms, you have to rewrite the ids so they are relative to their new parent plugin.
Second, I added the following entries to our jar's MANIFEST.MF:
Premain-Class: org.datanucleus.enhancer.DataNucleusClassFileTransformer
Bundle-SymbolicName: org.datanucleus;singleton:=true
This solution is not ideal as our application is essentially pretending to be the DataNucleus core OSGi bundle. However, this was what I ended up with after a few days off smashing my head on my desk.
It might be possible to provide a different PluginRegistry implementation, but I have not looked into this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With