/commands/java/create-executable-jar
jar --create --main-class: create an executable JAR and run it with java -jar
- tool
- Java
- versions
- Java 9+ (--create, --main-class), jar cfe: Java 6+
- os
- linux, macos, windows
jar --create --file app.jar --main-class com.example.App -C out . packs the compiled classes in out/ into app.jar and writes a manifest with Main-Class: com.example.App. Then java -jar app.jar starts that class. The short, older form of the same command is jar cfe app.jar com.example.App -C out ..
Build and run an executable JAR
mkdir -p src/com/example
cat > src/com/example/App.java <<'EOF'
package com.example;
public class App {
public static void main(String[] args) {
System.out.println("running from " + App.class.getProtectionDomain().getCodeSource().getLocation().getPath().replaceAll(".*/", ""));
System.out.println("args: " + String.join(" ", args));
}
}
EOF
javac -d out src/com/example/App.java
jar --create --file app.jar --main-class com.example.App -C out .
jar --list --file app.jar
mkdir check && cd check && jar --extract --file ../app.jar META-INF/MANIFEST.MF && cd ..
grep Main-Class check/META-INF/MANIFEST.MF | tr -d '
'
java -jar app.jar one twoOutput
META-INF/ META-INF/MANIFEST.MF com/ com/example/ com/example/App.class Main-Class: com.example.App running from app.jar args: one two
-C out . changes into out/ and adds everything there, so the JAR holds com/example/App.class at the right path. Arguments after the JAR file name go to main. Manifest lines end with CR LF, which is why tr strips the carriage return before printing.
Without a Main-Class
A JAR made without --main-class cannot be started with java -jar:
mkdir -p out/com/example
echo 'package com.example; public class App { public static void main(String[] a) { System.out.println("ok"); } }' > App.java
javac -d out App.java
jar --create --file plain.jar -C out .
java -cp plain.jar com.example.App
java -jar plain.jarOutput · exit 1
ok no main manifest attribute, in plain.jar
Running the class explicitly with -cp still works; -jar needs the manifest entry and otherwise stops with no main manifest attribute, in plain.jar and exit status 1.
jar options
| Command | What it does |
|---|---|
| jar --create --file app.jar --main-class X -C out . | Create an executable JAR from the out folder |
| jar cfe app.jar X -C out . | Same with the short options (c create, f file, e entry point) |
| jar --create --file app.jar --manifest manifest.txt -C out . | Use your own manifest lines, for example Class-Path |
| jar --list --file app.jar (jar tf app.jar) | List the entries |
| jar --update --file app.jar --main-class X | Add or change the entry point of an existing JAR |
| jar --describe-module --file app.jar | Show module information of a modular JAR |
Dependencies with Class-Path
When the program needs other JARs, add a Class-Path line to the manifest. The entries are relative URLs separated by spaces, resolved from the folder of the JAR:
Class-Path: lib/greeter.jar lib/json.jarCreate the JAR with --manifest manifest.txt (the file must end with a newline, or the last line is ignored) and ship the lib/ folder next to it.
Pitfalls
- Could not find or load main class from
java -jarmeans theMain-Classvalue does not match a class inside the JAR, often because-Cwas missing and the classes were stored underout/com/.... - UnsupportedClassVersionError on another machine means the JAR was compiled for a newer Java; compile with
javac --release Nfor the oldest Java you support. - -cp is ignored when you use
-jar; put dependencies in the manifest instead.
Confirm it worked
jar --list --file app.jar shows the class files at their package paths and META-INF/MANIFEST.MF; java -jar app.jar runs without extra arguments.
FAQ
What does no main manifest attribute mean?
The JAR's META-INF/MANIFEST.MF has no Main-Class entry, so java -jar does not know which class to start. Rebuild it with --main-class (or e in jar cfe), or run a class directly with java -cp app.jar com.example.App.
Does java -jar use my -cp or CLASSPATH?
No. With -jar, the JAR is the only class path entry, plus the Class-Path attribute of its manifest. -cp and the CLASSPATH variable are ignored.
How do I include dependencies in one JAR?
The jar tool cannot merge other JARs into yours. Either list them in the manifest Class-Path and ship them next to the JAR, or build a fat JAR with a build tool plugin such as the Maven Shade plugin or the Gradle Shadow plugin.