I'm trying to build an executable jar from the command line (I don't want to use ant or OneJar ) . Here is the content of my file.jar:
jar tvf file.jar
0 Mon Sep 20 17:16:12 CEST 2010 lib/
45396 Mon Sep 20 17:16:12 CEST 2010 lib/org.apache.commons.logging_1.0.4.v201005080501.jar
321330 Mon Sep 20 17:16:12 CEST 2010 lib/org.apache.commons.httpclient_3.1.0.v201005080502.jar
55003 Mon Sep 20 17:16:12 CEST 2010 lib/org.apache.commons.codec_1.3.0.v20100518-1140.jar
0 Mon Sep 20 19:15:00 CEST 2010 META-INF/
265 Mon Sep 20 19:12:44 CEST 2010 META-INF/MANIFEST.MF
530609 Mon Sep 20 17:16:12 CEST 2010 ped.jar
the content of META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Class-Path: ped.jar lib/org.apache.commons.codec_1.3.0.v20100518-1140.jar lib/org.apache.commons.httpclient_3.1.0.v201005080502.jar lib/org.apache.commons.logging_1.0.4.v201005080501.jar
Main-Class: fr.inserm.umr915.bomcat.ped.PedigreeDrawer
and the ped.jar do contains the Main-Class
jar tvf ped.jar | grep PedigreeDrawer.class
39541 Mon Sep 20 17:16:10 CEST 2010 fr/inserm/umr915/bomcat/ped/PedigreeDrawer.class
but when I'm trying to execute the file.jar, I got an error:
java -jar file.jar
Exception in thread "main" java.lang.NoClassDefFoundError: fr/inserm/umr915/bomcat/ped/PedigreeDrawer
Caused by: java.lang.ClassNotFoundException: fr.inserm.umr915.bomcat.ped.PedigreeDrawer
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
So, I'm missing something here. Can't I package an executable jar by just including the dependencies ?
Thanks for your help
Pierre
As already mentioned the jars in the Class-Path:
attribute are relative to the loaction of the jar file and not inside the jar file. This is probably a remnant from the days Java was meant to run applets.
You'll need to use a tool like maven uberjar to clobber all needed classes together in a single jar to create a standalone executable jar.
You can of course also just unzip all jars in a single directory, add the META-INF and manifest and zip everything up again if you absolutely want to avoid using tools.
what is file.jar?
you can try set class-path like this:
Class-Path: lib/org.apache.commons.codec_1.3.0.v20100518-1140.jar lib/org.apache.commons.httpclient_3.1.0.v201005080502.jar lib/org.apache.commons.logging_1.0.4.v201005080501.jar
and run your jar file like this:
java -jar ped.jar
You cannot include a Jar inside of a Jar without special packaging (e.g. OneJar, etc).
If you really do not want to use OneJar (or other similar tools), you will need to include multiple Jar files in your distributable.
The value "Class-Path" in your file manifest.mf
specifies your classpath as if you would start your application without the -jar
but with -classpath lib/...
parameter. The pathes are interpreted locally and not within your jar file.
An alternative is using one-jar or using a special classloader that looks into the jar files contained in your outer jar file.
With JCL you can load your classes directly from embedded jars like this:
JarClassLoader jcl=new JarClassLoader();
jcl.add("myjar.jar"); // Add some class source
jcl.getSystemLoader().setOrder(1); // Look in system class loader first
jcl.getLocalLoader().setOrder(2); // if not found look in local class loader
jcl.getParentLoader().setOrder(3); // if not found look in parent class loader
jcl.getThreadLoader().setOrder(4); // if not found look in thread context class loader
jcl.getCurrentLoader().setOrder(5); // if not found look in current class loader
// A custom class loader that extends org.xeustechnologies.jcl.ProxyClassLoader
MyLoader loader=new MyLoader();
loader.setOrder(6);
jcl.addLoader(loader); //Add custom loader
But then you have to add jcl to your classpath instead... or add an exploded jcl to your jar.
OneJar is meant to solve this kind of problem. You may write a custom classloader to same effect.