Published by marc at 2007.01.07
in Code.
The latest revision of the CFCL fixes a fatal bug and is greatly simplified over the previous version.
The first version of was a lot more complex that it needed to be. In a misguided attempt to avoid a recursive loader invocation, I had ClasspathFileClassLoader extend ClassLoader, and used an inner class that extended URLClassLoader. This meant that CFCL should have obeyed the standard classloader rules of engagement, which it unfortunately didn’t.
Requests to the inner URLClassLoader were always made using findClass(), which (for all but the simplest of applications) will result in a ‘duplicate definition’ error when a load is requested for a class that has already been defined. What CFCL should have done is first issue a findLoadedClass() request, and only if that returned null attempt to load the class using findClass().
As it turns out, its not a problem have CFCL extend URLClassLoader; this greatly simplifies the code as the inner class is no longer necessary, and CFCL can simply rely on URLClassLoader to correctly implement the required class loader semantics. This also makes the class much easier to maintain because I no longer have to worry about managing resource loading, signers, etc; something I would have had to do had CFCL continued as a facade.
Published by marc at 2007.01.01
in Code.
As a self-confessed command-line junkie, the amount of work that is required to start a Java application has always bothered me. The command-line for any application that requires more than one or two .jar files or class file directories to be specified quickly becomes a nightmare to type, and one very often has to resort to a shell script. While I have no problem with shell scripts per se, it seems only slightly less inconvenient to write a shell script for every application (with its own unique classpath) that I want to run, than it is to type the command-line for that application (especially when writing throwaway test classes).
As a first step to reducing the overhead involved in setting up a classpath, I have written a class loader that is able to read the classpath elements from a (set of) files.
Each line in the file must represent either a directory or .jar file that would normally be added using the -classpath switch. One can also use a #include directive to specify a directory that must be searched (non-recursively) for .jar files that must be added to the classpath. If the #import directive to include a regular file, that file will be read as a classpath file. For example, a classpath file may look something like:
#include /usr/local/lib/javalibdir
#include /home/user/directory/.classpathfile
/some/relative/directory/lib.jar
The initial classpath file is specified using the system property tierseven.cfcl.ClasspathFileClassLoader.file and the system property tierseven.cfcl.ClasspathFileClassLoader.verbose may be used to activate debug output. The class loader itself should be installed as the system class loader by using the system property java.system.class.loader. For example:
java -Djava.system.class.loader=tierseven.cfcl.ClasspathFileClassLoader -Dtierseven.cfcl.ClasspathFileClassLoader.file=.classpath -classpath . <main_class> <cmd_line_parameters>
This is still really much longer than i’d like it to be (mostly because of the properties) but at least this can be used in a generic shell script that can be used to start any application (if the classpath file location is parameterised).The source is available under the BSD license and is a work in progress.