Friday, June 27, 2008

Putting the Current Directory in the CLASSPATH

Someone from our users group posed a good question. Should you put the current directory in the CLASSPATH? Does it represent any security issues like on UNIX?

Here is the answer...depends, but it is generally a bad idea. Here is an example. I created a class called TestCase. It calls another class called ClassA in a jar file called ExampleJar.jar. I put another class called ClassA in the current directory and set the CLASSPATH as a passed parameter

java -classpath .:./lib/ExampleJar.jar TestCase
Here are the classes:


1 public class TestCase {
2
3 public TestCase() {
4 }
5
6 public static void main(String[] args) {
7 ClassA a = new ClassA();
8 a.print();
9 }
10 }


1 public class ClassA {
2
3 public void print() {
4 System.out.println("I am ClassA in a jar.");
5 }
6 }


1 public class ClassA {
2
3 // Bad apple!!!
4 public void print() {
5 System.out.println("I am ClassA in the wild...");
6 }
7 }


The question becomes which one of the ClassA files gets called? The legitimate one, or the bad apple?

[sundev:Desktop:root]#java -classpath .:lib/ExampleJar.jar TestCase
I am ClassA in the wild...
If I reverse the order to java -classpath lib/ExampleJar.jar:. TestCase

I get the expected result:

[sundev:Desktop:root]#java -classpath lib/ExampleJar.jar:. TestCase
I am ClassA in a jar.
The Classloader finds the first instance of the class which matches the appropriate signature and loads it. Subsequent classes of the same name and signature are not loaded.

Why does it matter?

The inclusion of the current directory into the CLASSPATH represents a potential security risk, also it may produce unexpected results from similarly named classes. The second item may be a bit more contrived in general terms, i.e. com.abc.ClassA and com.cba.ClassA are called ClassA, but are in different packages. This will not represent a problem.

The security issue can be real. A lot of programs that do installs on Windows specifically, add the CLASSPATH variable to the Windows environment and put the . (period) first. I checked my installation and found it to be the case. I would not knowingly put it there myself. Also I checked a couple of tutorials which suggest that you should do it for convenience. That piece is quickly forgotten 200 pages ago.

ADDENDUM:

Java 6 SE (J6SE) has added some additional enhancements around classpath. You can use the * (asterisk) wildcard to include all files in the classpath:

java -cp "*"; TestCase (Windows)
java -cp '*' TestCase (Unix/OS X)

Mark Reinhold has a blog entry entitled Class-Path Wildcards in Mustang which details it.

4 comments :

Unknown said...

You know, I searched everywhere, I can't find how to specify the current classpath and all subsequent directories and jar/zips underneath it on the classpath. Everywhere I look, I see people saying that "." is the current directory, but not in a working example. I think your post is the only one that comes closest to it. So it should be -cp . right? If -cp does not search recursively in ., then what if i want to search under a folder which is under .? would that be: -cp .;./lib/*?

John Yeary said...

The . (period) indicates the current directory. For example, if I created a class called Hello.java and did not assign it a package, when I compiled it I could run it by simply issuing the command java Hello.

I created a directory called test. I assigned hello to the test package and moved it to the test directory. I compiled the class and created a jar file. I placed the file in a directory called t1.

I then ran it with the command:
java -cp ./t1/* test.Hello
Hello World!

This resulted in what you expected by recursively looking into the directory to find the jar files and load them.

javin paul said...

Hi,

Its worth noting that if you have two classes with same name in classpath in that case one which comes earlier in classpath will get picked up. this concept is very useful to test patch releases where you update only few classes to quickly test patch release or have added some debug print statement to troubleshoot any issue. to read more about How classpath works in Java

Thanks
Javin
FIX Protocol Interview Questions

John Yeary said...

This is true. Even in our case where we use it for patches, I avoid using the wildcard, and "." in it.

Popular Posts