Basically, if the jar has a META-INF/INDEX.LST file then this needs to list all of the packages used, including those in “Class-Path” jars as well as those in the containing jar itself. This makes perfect sense once you realize what the purpose of INDEX.LST is and how it is used, as defined in the Jar File Specification.
But I wish I’d know about this when starting out! Two hours of double-checking the manifest’s “Main-Class” and “Path-Class” entries and looking for typos or syntax errors; trying different relative locations for the dependent jars; and reading and re-reading umpteen articles on how to make jars executable (none of which mentioned INDEX.LST).
It’s probably all very obvious to anyone that deals with this stuff all the time, but it’s not something I’ve had to dig into very often, and I guess I was a bit unlucky in what I thought I already know and the documentation that I came across along the way. I was also somewhat misled by seeing INDEX.LST as an “optimization” and taking this as meaning a speed-up that doesn’t actually affect behaviour – and therefore didn’t look more closely at exactly what it does. I really ought to know better, but from the content of the forum messages I’m not the only one who has been bitten by this.
So, just to spell this out for future reference, to make a jar executable when it uses classes and resources from other jars:
- Its manifest needs a “Main-Class” entry specifying the canonical class name of the class whose “main” method is to be invoked.
- Its manifest needs a “Class-Path” entry listing the other jars that need to be on the class path. This is a space-separated list of jars specified by their location “relative” to the executable jar’s own location (in the URI sense of “relative”: essentially, an absolute or relative path within the same host). In particular, if the jars will all be in the same directory, these are just the jar names on their own.
- The syntax of manifest files is rather sensitive and pedantic, so you need to take care over exact spacing, line length, continuation lines etc.
- When invoking the jar (typically as “java -jar xxxx.jar”), the java command ignores any “-cp” or “-classpath” argument, as the classpath is determined from the “Class-Path” entry of the jar’s manifest instead.
- But in addition: The executable jar must either not have a META-INF/INDEX.LST file, or if it does have such an INDEX.LST file this needs to list the contents of both the executable jar and all of the other jars as well. Anything not in this list will not be found on the class path, regardless of the “Class-Path” entry in the manifest and regardless of any command-line “-classpath” (which is ignored anyway).
If you are using the Apache Ant jar task to build the jar, you can set the task’s “index” attribute to false to prevent it from generating the INDEX.LST file (with this being the default), or (for Ant 1.6.2 onwards) you can set it to true and supply a nested “indexjars” element to specify the jars whose contents should be included in the INDEX.LST file (though depending on your build process and the relationships between the jars, this might be more trouble than it’s worth).
In general I guess INDEX.LST should only be included if the jars are actually intended for loading over a network, where it serves its purpose of optimizing the fetching of the jars. In other scenarios it just introduces more complexity, undesirable dependencies and more ways for classes to not be found, so it’s probably simpler and safer to omit it.
It has always seemed to be just asking for trouble to have jar files specifying internally what other jars they need plus exactly what they are called, where they are located and what they contain… and to prevent any external setting of the classpath or any installation-specific configuration… but that’s jars for you: welcome to “jar hell”.
Hopefully JSR 277 (Java Module System) will sort some of this out and give us a much better approach for handling dependencies between jars.