Java Using CLASSPATH Effectively

Java Using CLASSPATH Effectively


Problem 

You need to keep your class files in a common directory, or you’re wrestling with CLASSPATH. 

Solution 

Set CLASSPATH to the list of directories and/or JAR files that contain the classes you want. 

Explained

CLASSPATH is one of the more “interesting” aspects of using Java. You can store your class files in any of a number of directories, JAR files, or zip files. Just like the PATH your system uses for finding programs, the CLASSPATH is used by the Java runtime to find classes. Even when you type something as simple as java HelloWorld, the Java interpreter looks in each of the places named in your CLASSPATH until it finds a match. Let’s work through an example.

The CLASSPATH can be set as an environment variable on systems that support this (Unix, including Mac OS X, and Windows). You set it the same way you set other environment variables, such as your PATH environment variable. 

Alternatively, you can specify the CLASSPATH for a given command on its command line: 

java -classpath \c:\ian\classes MyProg 

Suppose your CLASSPATH were set to C:\classes;. on Windows or ~/classes:. on Unix (on the Mac, you can set the CLASSPATH with JBindery). Suppose you had just compiled a file named HelloWorld.java into HelloWorld.class and tried to run it. On Unix, if you run one of the kernel tracing tools (trace, strace, truss, ktrace), you would probably see the Java program open (or stat, or access) the following files:

• Some file(s) in the JDK directory.
• Then ~/classes/HelloWorld.class, which it probably wouldn’t find.
• And ./HelloWorld.class, which it would find, open, and read into memory.

The vague “some file(s) in the JDK directory” is release-dependent. On Sun’s JDK it can be found in the system properties: 

sun.boot.class.path = C:\JDK1.4\JRE\lib\rt.jar;C:\JDK1.4\JRE\lib\i18n.jar;C:\JDK1.4\
JRE\classes 

The file rt.jar is the runtime stuff; i18n.jar is the internationalization; and classes is an optional directory where you can install additional classes. 

Suppose you had also installed the JAR file containing the supporting classes for programs from this book, darwinsys.jar. You might then set your CLASSPATH to C:\ classes;C:\classes\darwinsys.jar;. on Windows or ~/classes:~/classes/darwinsys.jar:. on Unix. Notice that you do need to list the JAR file explicitly. Unlike a single class file, placing a JAR file into a directory listed in your CLASSPATH does not suffice to make it available. 

Note that certain specialized programs (such as a web server running Java Servlets) may not use either bootpath or CLASSPATH as shown; these application servers typically provide their own ClassLoader.

Another useful tool in the JDK is javap, which, by default, prints the external face of a class file: its full name, its public methods and fields, and so on. If you ran a command like javap HelloWorld under kernel tracing, you would find that it opened, looked around in, and read from a file \jdk\lib\tools.jar, and then got around to looking for your HelloWorld class, as previously. Yet there is no entry for this in your CLASSPATH setting. What’s happening here is that the javap command sets its CLASSPATH internally to include the tools.jar file.

If it can do this, why can’t you? You can, but not as easily as you might expect. If you try the obvious first attempt at doing a setProperty("java.class.path") to itself, plus the delimiter, plus jdk/lib/ tools.jar, you won’t be able to find the JavaP class (sun.tools.java.JavaP); the CLASSPATH is set in the java.class.path at the beginning of execution, before your program starts. You can try it manually and see that it works if you set it beforehand:

C:\javasrc>java -classpath /jdk1.4/lib/tools.jar sun.tools.javap.JavaP
Usage: javap  ...

If you need to do this in an application, you can either set it in a startup script, as we did here, or write C code to start Java.

How can you easily store class files in a directory in your CLASSPATH? The javac command has a -d dir option, which specifies where the compiler output should go. For example, using -d to put the HelloWorld class file into my /classes directory, I just type: 


javac -d /classes HelloWorld.java 

As long as this directory remains in my CLASSPATH, I can access the class file regardless of my current directory. That’s one of the key benefits of using CLASSPATH. 

Managing CLASSPATH can be tricky, particularly when you alternate among several JVMs (as I do) or when you have multiple directories in which to look for JAR files. You may want to use some sort of batch file or shell script to control this. Here is part of the script that I use. It was written for the Korn shell on Unix, but similar scripts could be written in the C shell or as a DOS batch file.


# These guys must be present in my classpath...
export CLASSPATH=/home/ian/classes/darwinsys.jar: 


# Now a for loop, testing for .jar/.zip or [ -d ... ]
OPT_JARS="$HOME/classes $HOME/classes/*.jar
 ${JAVAHOME}/jre/lib/ext/*.jar
 /usr/local/antlr-2.6.0" 
for thing in $OPT_JARS 

do 

if [ -f $thing ]; then //must be either a file... 

CLASSPATH="$CLASSPATH:$thing"  

else if [ -d $thing ]; then //or a directory 

CLASSPATH="$CLASSPATH:$thing" 

fi 

done 
CLASSPATH="$CLASSPATH:."

This builds a minimum CLASSPATH out of darwinsys.jar, then goes through a list of other files and directories to check that each is present on this system (I use this script on several machines on a network), and ends up adding a dot (.) to the end of the CLASSPATH.

0 comments:

Post a Comment