When you package your application, you want to give your users a single file, not a directory structure filled with class files. Java Archive (JAR) files were designed for this purpose. A JAR file can contain both class files and other file types such as image and sound files. Moreover, JAR files are compressed, using the familiar ZIP compression format.
1. Creating JAR files
Use the jar tool to make JAR files. (In the default JDK installation, it’s in the jdk/bin directory.) The most common command to make a new JAR file uses the following syntax:
jar cvf jarFileName file1 file2 . . .
jar cvf CalculatorClasses.jar *.class icon.gif
In general, the jar command has the following format:
jar options file1 file2 . . .
Table 4.2 lists all the options for the jar program. They are similar to the options of the UNIX tar command.
You can package application programs and code libraries into JAR files. For example, if you want to send mail in a Java program, you use a library that is packaged in a file javax.mail.jar.
2. The Manifest
In addition to class files, images, and other resources, each JAR file contains a manifest file that describes special features of the archive.
The manifest file is called MANIFEST.MF and is located in a special META-INF subdirectory of the JAR file. The minimum legal manifest is quite boring—just
Complex manifests can have many more entries. The manifest entries are grouped into sections. The first section in the manifest is called the main section. It applies to the whole JAR file. Subsequent entries can specify properties of named entities such as individual files, packages, or URLs. Those entries must begin with a Name entry. Sections are separated by blank lines. For example:
lines describing this archive
lines describing this file
lines describing this package
To edit the manifest, place the lines that you want to add to the manifest into a text file. Then run
jar cfm jarFileName manifestFileName . . .
For example, to make a new JAR file with a manifest, run
jar cfm MyArchive.jar manifest.mf com/mycompany/mypkg/*.class
To update the manifest of an existing JAR file, place the additions into a text file and use a command such as
jar ufm MyArchive.jar manifest-additions.mf
3. Executable JAR Files
You can use the e option of the jar command to specify the entry point of your program—the class that you would normally specify when invoking the java program launcher:
jar cvfe MyProgram.jar com.mycompany.mypkg.MainAppClass files to add
Alternatively, you can specify the main class of your program in the manifest, including a statement of the form
Do not add a .class extension to the main class name.
With either method, users can simply start the program as
java -jar MyProgram.jar
Depending on the operating system configuration, users may even be able to launch the application by double-clicking the JAR file icon. Here are behaviors for various operating systems:
- On Windows, the Java runtime installer creates a file association for the “.jar” extension that launches the file with the javaw -jar command. (Unlike the java command, the javaw command doesn’t open a shell window.)
- On Mac OS X, the operating system recognizes the “.jar” file extension and executes the Java program when you double-click a JAR file.
However, a Java program in a JAR file does not have the same feel as a native application. On Windows, you can use third-party wrapper utilities that turn JAR files into Windows executables. A wrapper is a Windows program with the familiar .exe extension that locates and launches the Java virtual machine (JVM) or tells the user what to do when no JVM is found. There are a number of commercial and open source products, such as Launch4J (http://launch4j .sourceforge.net) and IzPack (http://izpack.org).
4. Multi-Release JAR Files
With the introduction of modules and strong encapsulation of packages, some previously accessible internal APIs are no longer available. For example, JavaFX 8 had an internal class com.sun.javafx.css.CssParser. If you used it to parse a style sheet, then you will find that your program no longer compiles. The remedy is simple—switch to javafx.css.CssParser, which is available in Java 9. But now you have a problem. You need to distribute different applications for Java 8 and Java 9 users, or you need to play tricks with class loading and reflection.
To solve problems such as this one, Java 9 introduces multi-release JARs that can contain class files for different Java releases.
For backwards compatibility, the additional class files are placed in the META-INF/versions directory:
Suppose the Application class makes use of the CssParser class. Then the legacy Application.class file can be compiled to use com.sun.javafx.css.CssParser, while the Java 9 version uses javafx.css.CssParser.
Java 8 knows nothing about the META-INF/versions directory and will simply load the legacy classes. When the JAR file is read by Java 9, the new version is used instead.
To add versioned class files, use the –release flag:
jar uf MyProgram.jar –release 9 Application.class
To build a multi-release JAR file from scratch, use the -C option and switch to a different class file directory for each version:
jar cf MyProgram.jar -C bin/8 . –release 9 -C bin/9 Application.class
When compiling for different releases, use the –release flag and the -d flag to specify the output directory:
javac -d bin/8 –release 8 . . .
As of Java 9, the -d option creates the directory if it doesn’t exist.
The –release flag is also new with Java 9. In older versions, you needed to use the -source, -target, and -bootclasspath flags. The JDK now ships with symbol files for two prior versions of the API. In Java 9, you can compile with –release set to 9, 8, or 7.
Multi-release JARs are not intended for different versions of a program or library. The public API of all classes should be the same for both releases. The sole purpose of multi-release JARs is to enable a particular version of your program or library to work with multiple JDK releases. If you add functionality or change an API, you should provide a new version of the JAR instead.
5. A Note about Command-Line Options
The options of commands in the Java Development Kit have traditionally used single dashes followed by multiletter option names, such as
java -jar . . .
javac –Xlint:unchecked -classpath . . .
The exception was the jar command, which followed the classic option format of the tar command without dashes:
jar cvf . . .
Starting with Java 9, the Java tools are moving towards a more common option format where multiletter option names are preceded by double dashes, with single-letter shortcuts for common options. For example, the Linux ls command can be called with a “human-readable” option as
As of Java 9, you can use –version instead of -version and –class-path instead of -classpath. As you will see in Chapter 9 of Volume II, the –module-path option has a shortcut -p.
You can find the details in the JEP 293 enhancement request at http://openjdk .java.net/jeps/293. As part of this cleanup, the authors also propose to standardize option arguments. Arguments of options with — and multiple letters are separated by whitespace or an = sign:
javac –class-path /home/user/classdir . . .
Arguments of single-letter options can be separated by whitespace or directly follow the option:
javac -p modutedir . . .
This has created a muddle that will hopefully get cleaned up over time. As much as we’d like to move away from the archaic jar options, it seems best to wait until the dust has settled. But if you want to be thoroughly modern, you can safely use the long options of the jar command:
jar –create –verbose –file jarFileName file1 file2 . . .
Single-letter options also work if you don’t group them:
jar -c -v -f jarFileName file1 file2 . . .
Source: Horstmann Cay S. (2019), Core Java. Volume I – Fundamentals, Pearson; 11th edition.