12. Maven
Programming Project 2021/22

12.2. Compiling Java

Java compile process

Diagram from this medium.com article.

Java packaging

Java deployment

  • Thin jars are often used to deploy libraries or partial applications.
  • Fat jars are often used to deploy complete applications that do not require application servers.
  • Wars and ears are often used to deploy complete applications that require application servers, e.g., Apache Tomcat, JBoss, Jetty.
  • Docker images are often used to deploy complete applications.
    • Growing popular in last few years.

Compiling Java from the command line

Let us create a simple HelloWorld.java

public class HelloWorld {

  public static void main(String[] args) {
    System.out.println("Hello there!");
  }
}

We can compile it by running the following.

$ javac HelloWorld.java

We will now find a HelloWorld.class file in the current directory, which we can run by doing:

$ java HelloWorld

We should see the output below in the terminal:

Hello there!

Creating jar files from the command line

We can create a jar file by running:

$ jar cf hello.jar HelloWorld.class

We will now find a hello.jar file in the current directory, which we can run.

$ java -classpath hello.jar HelloWorld

We should see the following output in our terminals.

Hello there!

We can see what is inside our compiled class.

$ unzip hello.jar -d tmp

In the tmp directory we will find our HelloWorld.class and a META-INF folder containing a MANIFEST.MF file.

The MANIFEST.MF file

Whenever we create a jar file, a default manifest file is created.

Manifest-Version: 1.0
Created-By: 13.0.1 (Oracle Corporation)

A manifest's entries take the form of "header: value" pairs.

The manifest can also contain information about the other files that are packaged in the archive.

Exactly what file information should be recorded in the manifest depends on how you intend to use the JAR file.

Read more here.

Creating a runnable jar

To create a runnable jar, we first need to create a Manifest.txt as shown below. Make sure there is an empty line at the end of your file!

Main-Class: HelloWorld

Then, we run the following command:

$ jar cfm runnable-hello.jar Manifest.txt HelloWorld.class 

We can now simply run our program by executing:

$ java -jar runnable-hello.jar

We should see the following output:

Hello there!

Using 3rd party jars

Now, suppose that we want to use the Apache Commons Lang library

import org.apache.commons.lang3.StringUtils;

public class HelloWorld {

  public static void main(String[] args) {
    System.out.println("Hello there!");
    System.out.println("Is \"    \" an empty string? " + StringUtils.isBlank("    "));
  }
}

We need to download the appropriate jar file and make it available in our classpath when compiling and running our program

Given that we have a lib folder with the appropriate jar file, e.g., commons-lang3-3.12.0.jar, to compile, we can execute

$ javac -classpath ./lib/* HelloWorld.java

We should now have HelloWorld.class, our compiled file.

To run the program, we execute the following.

$ java -classpath './lib/*:./' HelloWorld

We should see the following output.

Hello there!
Is "    " an empty string? true

Creating a jar with a dependency

To create a runnable jar with a dependency, we must edit our Manifest.txt file.

Main-Class: HelloWorld
Class-Path: lib/commons-lang3-3.12.0.jar

Then, we run the following command:

$ jar cfm runnable-hello.jar Manifest.txt HelloWorld.class 

We can now simply run our program by executing:

$ java -jar runnable-hello.jar

We should see the following output:

Hello there!
Is "    " an empty string? true