Burak Dede's Blog

Where Is My Classes and Classpath?

What is the deal with classpath?

Ok I admit, I did not understand what is the use case for classpath when I started programming java or other JVM languages. But believe me, it is important. IDE and programming environments just shadow this knowledge with their fancy interfaces but you hit the wall hard when things get messy on production or whatever the environment you are running your application different from your fancy IDE.

Basically classpath is where java compiler (javac) and virtual machine (java) looks for your class files when they are referenced.

That is it, it seems trivial at first but searching mechanism is a bit more elaborate. By the way, I will show this case with java compiler javac but searching mechanism is not much different in virtual machine case. I will try to focus on search case not the verbosity of the java language, so I will try to use minimum classes.

The Classpath Case

Here are the two simple classes for our case.

package com.mycompany;
public class DBConnection {
    public static void main(String[] args) {
        System.out.println("This is the main method of DBConnection class\n");
    }
}
package com.mycompany;
public class User {
    public static void main(String[] args) {
        System.out.println("This is main method of User class\n");
        DBConnection db = new DBConnection();
    }
}

So two really fundamental classes, one is just for printing simple stuff, other both printing and only referencing it. No IDE help here so you have to create a simple structure manually for this project.

mkdir testj
cd testj
mkdir -p com/mycompany/
cp User.java DBConnection.java com/mycompany/

Above commands would make a simple structure for our test case.

You can name your root level folder whatever is suitable for your case. In my case, it is testj but tree structure must match com/mycompany/

Test Ride Classpath

Let’s first override the classpath and make compiler look nowhere for class search.

cd com/mycompany/
javac -classpath "" DBConnection.java

Above command will tell java compiler to look nowhere (in that case “”) for class files and try to compile **DBConnection” class. And it will success while doing that. It will not fail because compiler easily found the DBConnection file and it does not reference any other class.

cd com/mycompany/
javac -classpath "" User.java

Above command will fail and gives the following compile error.

User.java:5: error: cannot find symbol
        DBConnection db = new DBConnection();
        ^
  symbol:   class DBConnection
  location: class User

Why is that? All files needed to compile just there? Ok, compiler will try to find User class and had no problem doing that and after that it will see that there is DBConnection reference and try to find it in the same com/mycompany/DBConnection. Guess what? the compiler does not know where to look because we told it to look nowhere. Let’s change that to look for the current folder which is logical to do.

cd com/mycompany/
javac -classpath "." User.java

Still no luck, what is going on? Ok, we may be messed with compiler search thing when we gave it ”.” (current folder) path. Here is what compiler do in this case it will search again for DBConnection in com/mycompany but in this case, we gave it a current folder compiler will try to locate DBConnection in com/mycompany/com/mycompany which does not exist.

”..” is an upper directory in Unix case.

Let’s fix this mess and give it relative two level upper directories so that compiler can aim right folder for compilation.

javac -classpath "../../" User.java

That command will successfully compile both files and ready to run by the virtual machine. But it is kind of ugly because we are dealing with relative paths. Let’s change starting point to the root folder and give relative path from there.

cd ../../
javac -classpath "." com/mycompany/User.java

This will also compile and much better looking than the first successful one.

”.” does not mean look for the current folder for search but start from the current folder, it can go deeper if it wants.

We can also compile these two classes with single wildcard and not mess up with classpath much.

cd testj/com/mycompany
javac -classpath "." *.java

This will extend wildcard to match all the java files in that directory because compiler now has all reference in its hand compilation will be successfull.

Class Files and Java Files Hell

After compilation will place the .class files along with .java files so it not much a problem when you are working with two files but will be a mess for larger projects.

Class folder to the rescue!!!

cd testj
javac -d classes -classpath "." com/mycompany/*.java

This will compile all the files inside the com/company and place their output inside classes folder with related folder structure. When I mean related folder structure when you compile “com/mycompany/User.java” the output will be “com/mycompany/User.class” and will be in folder classes

That is all great we can compile and product output in whatever folder we want but this is kind of messy and can lead to errors.

Jar to the rescue!!!

I did not say Jar file because Jar is actually folder

jar cvf mylib.jar com/mycompany/*.class

When you use jar utility to package your java class files, you can give jar to classpath so that compiler peeks inside your jar file.

javac -classpath /myclasses/mylib.jar ...

There is also system CLASSPATH case even though it solves most of the problems by setting CLASSPATH environment variable and even better by adding it to your .bashrc it is easy to forget you have setted that and suprise yourself by compiler errors.


powered by TinyLetter