Wednesday, November 11, 2009

Fun with java jar manifest files.

So, I was trying to do a simple thing: Convert a jar file into a runnable jar file. Seems pretty simple, there is a nice tutorial here, for instance.


But, it took hours. It turns out that if you have an extra space in the manifest file, it will not be able to find your main class. Someone should have written some extra debugging in the java and/or jar command to make this much more obvious. Since they did not, hopefully someone will find this page before they waste 3 hours like I did! Another thing: The lines in the manifest file cannot be too long. If they are, it will auto-wrap, but it does a bad job of that too, so be sure to wrap them youself by hand, as I do with Class-Path below. The spaces in front of the jar
files must be there or the manifest will be treated as invalid.


This one works:


Class-Path: lfclient.jar
gnujaxp.jar jfreechart-1.0.13-experimental.jar
junit.jar
iText-2.1.5.jar jfreechart-1.0.13.jar jcommon-1.0.16.jar
jfreechart-1.0.13-swt.jar swtgraphics2d.jar .
Main-Class: candela.lanforge.lfclient


This one will not:


Class-Path: lfclient.jar
gnujaxp.jar jfreechart-1.0.13-experimental.jar
junit.jar
iText-2.1.5.jar jfreechart-1.0.13.jar jcommon-1.0.16.jar
jfreechart-1.0.13-swt.jar swtgraphics2d.jar .
Main-Class: candela.lanforge.lfclient


It will give an error like:

$ java -jar lfclient.jar
Exception in thread "main" java.lang.NoClassDefFoundError: candela/lanforge/lfclient
Caused by: java.lang.ClassNotFoundException: candela.lanforge.lfclient
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
Could not find the main class: candela.lanforge.lfclient. Program will exit.


Hard to see the difference, eh?