JAR Files and Executable JARs in Java

Naveen AnamaneniUpdated · 7 min read

A JAR (Java ARchive) is a single file that bundles compiled classes and resources such as images and configuration files. It is a ZIP file with one extra item: a manifest, a small text file with information about the archive. JARs are how Java code is distributed: every library you download is one. An executable JAR is a JAR whose manifest names a main class, so the whole application can be started with java -jar app.jar. In this lesson, you will learn how to create, inspect and run JAR files with the jar tool, what the manifest contains, and how a JAR can also be created from Java code.

The jar Tool

The JDK's jar command has long option names and older one-letter forms; both work.

TaskLong formShort form
Create a JARjar --create --file app.jar -C out .jar cf app.jar -C out .
Create with a main classjar --create --file app.jar --main-class com.school.Hello -C out .jar cfe app.jar com.school.Hello -C out .
List the contentsjar --list --file app.jarjar tf app.jar
Extractjar --extract --file app.jarjar xf app.jar
Updatejar --update --file app.jar -C out .jar uf app.jar -C out .
Create with your own manifestjar --create --file app.jar --manifest manifest.txt -C out .jar cfm app.jar manifest.txt -C out .

-C out . means "change to the folder out and add everything in it", so the paths inside the JAR start at the package root.

Example: Creating and Running an Executable JAR

Hello.java
package com.school;
 
public class Hello {
    public static void main(String[] args) {
        String name = args.length > 0 ? args[0] : "world";
        System.out.println("Hello, " + name + "!");
    }
}
Terminal
javac -d out src/com/school/Hello.java
jar --create --file hello.jar --main-class com.school.Hello -C out .
jar --list --file hello.jar
java -jar hello.jar Navika
Terminal output
META-INF/
META-INF/MANIFEST.MF
com/
com/school/
com/school/Hello.class
Hello, Navika!

Explanation:

  1. javac -d out compiles into the folder out, creating com/school/Hello.class.
  2. jar --create packs everything under out. --main-class writes the entry point into the manifest.
  3. jar --list shows the contents: the class in its package folders, plus META-INF/MANIFEST.MF, which the tool created.
  4. java -jar hello.jar Navika reads the manifest, finds the main class and runs it. Arguments after the JAR name go to main.

The Manifest

The manifest of that JAR is:

META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 25.0.5.0.3 (Homebrew)
Main-Class: com.school.Hello
AttributeMeaning
Manifest-VersionAlways present; the manifest format version
Created-ByThe JDK that built the JAR
Main-ClassThe class whose main method java -jar runs
Class-PathOther JARs this one needs, as space-separated relative paths
Automatic-Module-NameThe module name to use when the JAR is placed on the module path
Implementation-Title, Implementation-VersionDescriptive information about the library
Multi-Release: trueThe JAR holds different class versions for different Java releases

A manifest written by hand must end with a newline, or the last line is ignored. Each line is Name: value, with a space after the colon.

Executable vs Ordinary JAR

A JAR without Main-Class can't be started with -jar:

Terminal output
$ java -jar plain.jar
no main manifest attribute, in plain.jar

It can still be used on the class path, naming the class yourself:

Terminal
java -cp hello.jar com.school.Hello Srihitha
Terminal output
Hello, Srihitha!
java -jar app.jarjava -cp app.jar com.school.Hello
Needs Main-Class in the manifestYesNo
Class pathOnly the JAR and its manifest Class-Path; -cp is ignoredWhatever you list
Used forApplicationsLibraries, or choosing among several main classes

A JAR with Dependencies

When an application needs other JARs, there are three common ways to ship it:

ApproachHow
Class-Path in the manifestClass-Path: lib/h2.jar lib/util.jar, with those files placed next to the application JAR
A "fat" (uber) JARA build tool (Maven Shade, Gradle Shadow, Spring Boot) packs your classes and all dependencies into one JAR
A runtime image or installerSee "Jlink in Java: Custom Runtime Images" and "Jpackage in Java: Native Installers"

Modular JARs

A modular JAR is a JAR with a module-info.class at its root. The expense tracker from "Java Platform Module System (JPMS)" is packaged like this:

Terminal
jar --create --file mods/expenses.core.jar --module-version 1.0 \
    -C out/expenses.core .
jar --create --file mods/expenses.app.jar --module-version 1.0 \
    --main-class com.poolstring.expenses.app.Main -C out/expenses.app .
java --module-path mods -m expenses.app
Terminal output
By category: {Food=649.75, Travel=1200}
Total: 1849.75
Running in module: expenses.app

Because the JAR records its main class, -m expenses.app is enough; no class name is needed.

Example: Creating a JAR from Java Code

The package java.util.jar reads and writes JARs. Let's see an example that writes a small JAR with a manifest and two entries, then reads it back:

JarMaker.java▶ Try it
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
 
public class JarMaker {
    public static void main(String[] args) throws Exception {
        Path jarPath = Path.of("notes.jar");
 
        // Write a JAR: a manifest plus two entries.
        Manifest manifest = new Manifest();
        Attributes main = manifest.getMainAttributes();
        main.put(Attributes.Name.MANIFEST_VERSION, "1.0");
        main.put(Attributes.Name.MAIN_CLASS, "com.school.Hello");
        main.put(new Attributes.Name("Built-By"), "Navika");
 
        try (OutputStream out = Files.newOutputStream(jarPath);
             JarOutputStream jar = new JarOutputStream(out, manifest)) {
            jar.putNextEntry(new JarEntry("notes/readme.txt"));
            jar.write("A JAR is a ZIP file with a manifest.\n"
                .getBytes(StandardCharsets.UTF_8));
            jar.closeEntry();
            jar.putNextEntry(new JarEntry("notes/marks.csv"));
            jar.write("Navika,91\nSrihitha,84\nAdvitha,78\n"
                .getBytes(StandardCharsets.UTF_8));
            jar.closeEntry();
        }
 
        // Read it back.
        try (JarFile jar = new JarFile(jarPath.toFile())) {
            Attributes attrs = jar.getManifest().getMainAttributes();
            System.out.println("Main-Class: "
                + attrs.getValue(Attributes.Name.MAIN_CLASS));
            System.out.println("Built-By:   " + attrs.getValue("Built-By"));
            jar.stream().map(JarEntry::getName).sorted()
                .forEach(name -> System.out.println("entry: " + name));
            JarEntry csv = jar.getJarEntry("notes/marks.csv");
            String text = new String(jar.getInputStream(csv).readAllBytes(),
                StandardCharsets.UTF_8);
            System.out.println("marks.csv has " + text.lines().count()
                + " lines; first: " + text.lines().findFirst().orElse(""));
        } finally {
            Files.delete(jarPath);
        }
    }
}
Output
Main-Class: com.school.Hello
Built-By:   Navika
entry: META-INF/MANIFEST.MF
entry: notes/marks.csv
entry: notes/readme.txt
marks.csv has 3 lines; first: Navika,91

Explanation: Manifest and Attributes build the manifest, JarOutputStream writes entries one after another, and JarFile opens the result to read its manifest and entries. Build tools and application servers use these same classes.

Common Mistakes

"no main manifest attribute". The JAR has no Main-Class; rebuild with --main-class or run with -cp and the class name.

Wrong folder structure. If you jar the out folder itself instead of its contents, classes sit under out/com/... and can't be found. Use -C out ..

Expecting -cp to work with -jar. It is ignored; use the manifest's Class-Path.

A hand-written manifest with no final newline. The last attribute is silently dropped.

Interview Corner

What is a JAR file and how do you make it executable?

A JAR (Java ARchive) is a ZIP-format file that packages compiled classes, resources and a manifest at META-INF/MANIFEST.MF. It is created with the jar tool or a build tool. To make it executable, the manifest must contain a Main-Class attribute naming the class with the main method, for example via jar --create --file app.jar --main-class com.example.Main -C classes .; it then runs with java -jar app.jar. Dependencies can be listed in the manifest's Class-Path attribute or bundled into a fat JAR.

Practice

  1. Easy: Create an executable JAR for any small program of yours and run it with java -jar.
  2. Harder: Extract the manifest from a library JAR you use with jar --extract --file lib.jar META-INF/MANIFEST.MF and explain three of its attributes.

Quick check: JAR files

4 questions
1What file format is a JAR?
2Which manifest attribute makes a JAR executable?
3Which command lists the contents of app.jar?
4What happens to -cp when you use java -jar?

Key Takeaways

Was this tutorial helpful?

Lesson 517 of 578