Table of Contents
Overview
With the super power of modern IDEs, Java developers (maybe developers of other languages, too) don’t know how to work without them.
I don’t say this is bad but it’s cool to code without IDE (to understand the way Java compiler work, at a very basic level).
Compile a Java program and package to jar file
As you may already know, a jar file is actually a zip file. You can extract that file using unzip.
Let’s create a simple project that play as the role of a library. I’m going to write another program to import this library and call the library’s method.
package org.remote.lib; public class Common { public static void fromLib() { System.out.println("Hello from lib"); } }
This file named Common.java is located under org/remote/lib.
Now, let’s compile this and package into a jar file.
Compile the library:
javac org/remote/lib/Common.java
You should see no output after entering this command. That means the program was compiled successfully.
Let’s package the library in a jar file:
jar cf remote.jar org/remote/lib/Common.class
This will package the common library to a jar file named remote.jar, ready to be imported to other program, which I’m going to write next.
Write a Java program which import a Jar file
Let’s create another Java program in a different package. This time, it’s in com/local/java. The class name is TestJava.java
package com.local.java; import org.remote.lib.*; class TestJava { public static void main(String[] args) { System.out.println("hey from local"); //Test faker System.out.println("Calling from imported lib:"); Common.fromLib(); } }
As you can see, on line 2, I imported the library with full package name.
On line 11, I called the function from the library.
Let’s compile the TestJava class and try to run the program:
javac com/local/java/TestJava.java
Surprisingly, the compile will complain about missing package:
com\local\java\TestJava.java:2: error: package org.remote.lib does not exist
import org.remote.lib.*;
^
com\local\java\TestJava.java:11: error: cannot find symbol
Common.fromLib();
^
symbol: variable Common
location: class TestJava
2 errors
This error will not happen if you have both com/local/java and org/remote/lib sharing the same root. However, as I’m simulate the case where the library is compiled on a different server, the org and com directories should not be on the same parent directory.
To mitigate the problem, let’s add the remote.jar file in the classpath when compiling the TestJava program:
javac -cp remote.jar com/local/java/TestJava.java
This time, the compile didn’t complain and the program was complied just fine.
However, if you try to run the program now, you will get another error:
$ java com/local/java/TestJava hey from local Calling from imported lib: Exception in thread "main" java.lang.NoClassDefFoundError: org/remote/lib/Common at com.local.java.TestJava.main(TestJava.java:11) Caused by: java.lang.ClassNotFoundException: org.remote.lib.Common at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ... 1 more
It said that the class Common was not found under org/remote/lib.
When calling the program, you need to pass the classpath too.
So, this command will run the TestJava program just fine:
# This is for Windows java -cp ".;remote.jar" com/local/java/TestJava # This is for Unix/Linux java -cp ".:remote.jar" com/local/java/TestJava
You will get the following output:
Notice that I passed “.;remote.jar” to the -cp in the command line. The dot(.) tell the JVM that current folder is in class path too. Without that (if you include just the jar file), you will get another NoClassDefFound error.
Transitive dependencies
Transitive dependencies are dependencies of dependencies. That means if the org.remote.lib.Common
program above depends on another library (such as Lombok), you need to include Lombok jar in the classapth too.
This is where you miss tools like Maven/Gradle. They handle transitive dependencies for the developers.
Conclusion
As you can see, a simple program with no external dependencies is quite simple to build and run. However, things get complicated when there are imported libraries. Understand how to pass the libraries into the classpath helps you compile and run the program properly.
I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.