JarIndex seems to be useful for applets and networking. It can prevent from loading unnecessary archives.
Here we have a so called root jar which includes an INDEX.LIST
file and that file includes a mapping from class to library. The classloader will read the file, create an internal hashtable and use this table to determine, where a class can be found. If the library has not been loaded yet, then it will load it to load the class. Otherwise it would have to load all libraries at once just to resolve a single class (because a class name never gives any clue where a class can be found)
Once the classloader finds such an index, it trusts that information and will complain with an exception if the information is not true. Say the index tells the classloader that com.example.MyClass
can be found inside http://example.com/a.jar
, then it will download (if not already done) the jar and only look inside this library. If there's no such class it will not look in different jars (or even download additional jars) but will have a hump with you (and throw an exception).
If you encounter such an exception you might be pretty lost. The problem (corrupt INDEX.LIST file) can't be fixed on the consumers side. But because the classloader expects the INDEX.LIST
file in the first jar on the classpath, changing the order of libraries in the classpath expression could solve such a problem by disabling the indexer feature.
Further Reading
Working Example with ant
I created two very simple classes to print Hello world:
package test;
public class Hello {
public static void main(String[] args) {
System.out.println(HelloTextFactory.createResponse());
}
}
and
package test;
public class HelloTextFactory {
public static String createResponse() {
return "Hello world";
}
}
and an ant file (build.xml) to create the archives:
<project name="test">
<target name="jar" description="description">
<delete file="main.jar" />
<delete file="factory.jar" />
<jar destfile="factory.jar" includes="test/HelloTextFactory.class" basedir="bin" />
<jar destfile="main.jar" includes="test/Hello.class" basedir="bin" index="true">
<indexjars>
<fileset dir="." id="jars">
<include name="factory.jar" />
</fileset>
</indexjars>
<manifest>
<attribute name="Main-Class" value="test.Hello" />
<attribute name="Class-Path" value="factory.jar" />
</manifest>
</jar>
</target>
</project>
This build file assumes that the classes have been compiled into the bin
folder before running the script.
Running the build script creates two jars, main.jar contains an index and java -jar main.jar
runs successfully. Then I moved the second class into a different package and started the build again. And again, it created a working application.
During experimentation I realized that
- it is necessary to force creation of all jars, especially the main jar. If ant rebuilds
factory.jar
the index will not be updated and may be invalid. That's why I added the delete
tasks.
main.jar
has to be created after all other jars are created.