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 TestCaseHere 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?
If I reverse the order to java -classpath lib/ExampleJar.jar:. TestCase
[sundev:Desktop:root]#java -classpath .:lib/ExampleJar.jar TestCase
I am ClassA in the wild...
I get the expected result:
[sundev:Desktop:root]#java -classpath lib/ExampleJar.jar:. TestCaseThe 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.
I am ClassA in a jar.
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.
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/*?
ReplyDeleteThe . (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.
ReplyDeleteI 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.
Hi,
ReplyDeleteIts 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
This is true. Even in our case where we use it for patches, I avoid using the wildcard, and "." in it.
ReplyDelete