Most Read This Week
Fun with Resources and Class Loaders
Fun with Resources and Class Loaders
By: Brian Maso
May. 1, 1997 12:00 AM
There have been a lot of new APIs and facilities added to Java 1.1 that have received a lot of fanfare: the Java Database Connectivity API, the new event model, JavaBeans and so on. A lot of new functionality has also been added very quietly, probably because it's not quite as glamorous. I'd like to spend this month's column talking about one of these quiet new additions to Java, one that I have found to be very useful. This new addition is the new "resource" method added to the Java 1.1 ClassLoader class.
Java 1.0's ClassLoader class allows you to do one thing: load .CLASS files into the Java VM. The ClassLoader was a great thing, but I found it difficult to use for one major reason: you couldn't easily load resources associated with classes. For example, I wrote a hierarchical tree class and I wanted a couple of .GIF files to be available for use by my class. (One image is an "expanded node" indicator and the other is a "contracted node" indicator.)
Well, in Java 1.0 it was rather difficult to write classes which are dependant on image resources. I had to write a lot of code that detected if my hierarchical list was part of an applet or an application, and to construct URLs for my image files as best I could.
All that tortuous programming is gone in Java 1.1. Using the new ClassLoader "resource" methods, you can load arbitrary resource files as easily as you load .CLASS files. Take a look at Listing 1. This code loads an image file named "Example.gif" from the local file system. The listing uses the ClassLoader static class method loadSystemResource(). This method works by looking on the local file system for a file named "Example.gif" anywhere in the local system's classpath.
If you think about it, you can see how system classes (classes loaded from the local file system) are loaded. The class name first gets converted to a .CLASS file name. For example, the class name "com.maso.MyClass" gets converted to "com\maso\MyClass.class". The new string is nothing .more than a URL, or relative path name of a file. The second step is to use the static ClassLoader class method, getSystemResource(), to locate the .CLASS file. This will search the classpath for the given file. Once found, the third step is to load the .CLASS file into the Java VM. So, a system resource is any data file found along the system's class path, which usually includes .CLASS files.
Listing 2 shows how the same data files are loaded from within an applet. Within an applet environment, when you don't know what files are located on the local system's classpath you must use a different ClassLoader class method to load resource files. The getResource() method is an abstract method in the ClassLoader class, because it is up to each individual ClassLoader how to search for named resources.
The AppletViewer's AppletClassLoader uses this technique to find resource files when its getResource() method is called.
The first and third step existed in Java 1.0. That is, Java 1.0 worked the same as if the second step listed above were removed. So, the image files being loaded in Listing 2 can be located in one of three different places to be loaded corrected by the code: on the local file system (in the classpath), within a JAR file downloaded from the HTTP server or in the same directory as the applet .CLASS file on the HTTP server.
The big trick of this month's column is listed in Listing 3, which is the code listing of a utility class I like to use in my applications and applets in Java 1.1. The loadPackageResource() method of this class is able to load a data file associated with a given class and package, no matter what the context the code is running in. That is, the method will work just as well if is called from within an application (Listing 1), or an applet (Listing 2). For that matter, this method should also work if it is being called from other, more exotic contexts such as within a server-side Servlet, a JavaBean within an ActiveX/JavaBean bridge in a Visual Basic program, etc.
The loadPackageResource() method works by first determining the package name of the reference class. It is assumed that a package resource will be located in a directory named for the package the reference class is in. That is, if I asked the loadPackageResource() method to load a file named "Example.gif", using a reference class "com.maso.MyClass", then I would expect the loadPackageResource() method to look for a resource with the full name "com\maso\Example.gif". I want the method to locate the file using the same search technique used to locate the .CLASS file for the class MyClass.
I find the class shown in Listing 3 to be extremely useful now. It is probably one of the greatest optimizations in my Java code that I have experienced in converting to Java 1.1 from Java 1.0. No longer do I have to write complex class or context-specific code to load images (and different code to load audio files or arbitrary binary data files). Instead, I just call my trusty loadPackageResource() with a reference to the class that wants to use the resource data.
Listing 4 is a short excerpt of code demonstrating how the loadPackageResource() method would be used. This listing shows how a HierarchicalTree class could load its expanded and contracted node images. This same code will work regardless of whether the hierarchical list is being created within an applet or an application.
Note: Last month I challenged readers to come up with examples of using Java exceptions to optimize or make better Java implementations. Well, I haven't received anything yet. I encourage you readers to send in tricks of any sort, which I'll be sure to pass along (with proper attribution, of course).
Reader Feedback: Page 1 of 1
Subscribe to the World's Most Powerful Newsletters
Today's Top Reads