|Wednesday, July 3, 2002|
Java, the language, isn't bad -- just another programming language.
But java -- the command line interface to launching the JVM -- seriously sucks. In particular, the whole mechanism for managing the classpath is just plain stupid.
The truly painful part is that it has remained stupid throughout the entire lifetime of Java.
There is no way to append to the classpath; you can only set the whole bloody thing through one and only one of the three possible ways to set it (the -cp arg, the -classpath arg, or the CLASSPATH environment variable).
DUH! Did it not dawn on anyone at any point in time that, MAYBE, someone might want to create a baseline classpath, then add to it within the individual context of any particular invocation?
Apparently not. Instead, one is generally forced to write silly shell scripts for composing the classpath.
Of course, a number of shells have limits as to the size of environment variables or the length of the command line. Being able to add to the CLASSPATH via the -cp or -classpath command line argument certainly would have helped (not to mention being a convenient way to lay down a baseline and add to it contextually).
But that was too old skool for Sun. Instead, we have the whole magical extensions directory mechanism to make jars worth of classes automatically available, thereby reducing the size of the classpath (among other notably "features").
However, any class find via the extensions directory behaves differently than classes found on the classpath. A class loaded via the extensions class loader cannot use forName() to refer to classes that are only found within the classpath.
Any code that dynamically determines which class to use at runtime -- a common object oriented idiom -- is subsequently susceptible to really annoying potential failure.
You can easily find yourself in a situation where a pile of code will compile perfectly fine, but will fail at runtime. Because the compiler has no problem finding classes via both the extensions and the hardwired classpath, code that statically references a class can still fail at runtime if forName() is used.
To further infuriate the developer, it is quite easy to load a different version of a class inadvertently at runtime. Imagine if you have a later version of, say, the JDOM compiler explicitly hardwired in your classpath and have, say, an earlier version of the JDOM API in your extensions directory (production version in extensions, beta version hardwired in path).
Everything compiles fine as the compiler looks at the classpath, then extensions. At runtime, say a class in the extensions does a forName() to retrieve a class from jdom.jar. Since it is in the extensions class loader, it loads the old version from the extensions directory.
Generally, very bad things happen if your app tries to mix classes from two different versions of a jar file.
Stupid stupid stupid.
To make matters worse, there isn't a good tool [that I have found] for deducing exactly what classes are being loaded from where. The '-verbose:class' command line option only gives notice when a class is loaded -- you really need to know that jar file it was loaded from and the class loader that was used. As such, debugging problems such as these is incredibly frustrating.
Bottom line: Don't use the extensions directory(ies) for anything but stuff explicitly designed to be used with the extensions class loader. Instead, write stupid shell scripts to handle the classpath of everything on an individual basis.
*sigh* You would think that after 7 years of this stuff, there would have been some improvements in the CLI to the JVM. This does not seem to be the case.