JAR Files and Executable JARs in Java
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.
| Task | Long form | Short form |
|---|---|---|
| Create a JAR | jar --create --file app.jar -C out . | jar cf app.jar -C out . |
| Create with a main class | jar --create --file app.jar --main-class com.school.Hello -C out . | jar cfe app.jar com.school.Hello -C out . |
| List the contents | jar --list --file app.jar | jar tf app.jar |
| Extract | jar --extract --file app.jar | jar xf app.jar |
| Update | jar --update --file app.jar -C out . | jar uf app.jar -C out . |
| Create with your own manifest | jar --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
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 + "!");
}
}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 NavikaMETA-INF/
META-INF/MANIFEST.MF
com/
com/school/
com/school/Hello.class
Hello, Navika!Explanation:
javac -d outcompiles into the folderout, creatingcom/school/Hello.class.jar --createpacks everything underout.--main-classwrites the entry point into the manifest.jar --listshows the contents: the class in its package folders, plusMETA-INF/MANIFEST.MF, which the tool created.java -jar hello.jar Navikareads the manifest, finds the main class and runs it. Arguments after the JAR name go tomain.
The Manifest
The manifest of that JAR is:
Manifest-Version: 1.0
Created-By: 25.0.5.0.3 (Homebrew)
Main-Class: com.school.Hello| Attribute | Meaning |
|---|---|
Manifest-Version | Always present; the manifest format version |
Created-By | The JDK that built the JAR |
Main-Class | The class whose main method java -jar runs |
Class-Path | Other JARs this one needs, as space-separated relative paths |
Automatic-Module-Name | The module name to use when the JAR is placed on the module path |
Implementation-Title, Implementation-Version | Descriptive information about the library |
Multi-Release: true | The 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:
$ java -jar plain.jar
no main manifest attribute, in plain.jarIt can still be used on the class path, naming the class yourself:
java -cp hello.jar com.school.Hello SrihithaHello, Srihitha!java -jar app.jar | java -cp app.jar com.school.Hello | |
|---|---|---|
Needs Main-Class in the manifest | Yes | No |
| Class path | Only the JAR and its manifest Class-Path; -cp is ignored | Whatever you list |
| Used for | Applications | Libraries, or choosing among several main classes |
A JAR with Dependencies
When an application needs other JARs, there are three common ways to ship it:
| Approach | How |
|---|---|
Class-Path in the manifest | Class-Path: lib/h2.jar lib/util.jar, with those files placed next to the application JAR |
| A "fat" (uber) JAR | A build tool (Maven Shade, Gradle Shadow, Spring Boot) packs your classes and all dependencies into one JAR |
| A runtime image or installer | See "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:
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.appBy category: {Food=649.75, Travel=1200}
Total: 1849.75
Running in module: expenses.appBecause 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:
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);
}
}
}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,91Explanation: 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
- Easy: Create an executable JAR for any small program of yours and run it with
java -jar. - Harder: Extract the manifest from a library JAR you use with
jar --extract --file lib.jar META-INF/MANIFEST.MFand explain three of its attributes.
Key Takeaways
Was this tutorial helpful?