Java classes forming an application, Applet, or weblet can be bundled up into
something that looks very much like a ZIP file. JavaBeans are also packaged in JAR
files. In Java version 1.1 or later compression is turned on by
default and in earlier versions it was always off. It is faster to download a group
of classes as a single JAR file since HTTP (Hypertext Transfer Protocol)
has high overhead to set up a connection for each file transferred. The tools
Jar.exe and jarsigner.exe come bundled with the JDK (Java Development Kit).
Jar vs Zip
A JAR file differs from a standard ZIP in that:
Tips on Using Jar Files
- The directory path names stored inside the Jar should
exactly match the package names, no extra qualification. There must be no
drive letters. jar.exe won’t warn you if you
screw up! They must match in case precisely as well. Check with WinZip that you have not inadvertently
included C:\ in your directory/package names. Whatever
you put on the command line goes in raw as the path. You must thus juggle your
current directory before using jar.exe to make
things work out.
- You can put a data file inside the Jar file (a resource) and access it with
code like this:
where InWords.properties is the name of the file inside
the jar file you want to read. Class.getResource makes
these changes to the resource name: if the resource name starts with /, it is unchanged; otherwise, the package name is prepended to
the resource name after converting . to /. This allows you to use either dots or slashes to separate the
components of the name.
To get information out of jar files other than the main jar, you would need to
use ZipFile and
ZipEntry.getInputStream.
To see how to fish *.gifs and jpgs out of jar files, see Image.
- Unlike zips, jars are not compressed. So unless you gzip individual resources,
they will appear in the jar in uncompressed form.
- Names of resources and their paths are case-sensitive
in a jar. You may have been lulled into a false sense of security because, under
Windows, resources outside the jar are case-insensitive. When you pack your
application into a jar, it stops working.
- See the java.util.zip.ZipOutputStream class to write
jar files. Normally you manipulate them with jar.exe or WinZip.
- Microsoft Internet Explorer with Microsoft Java (now increasingly rare) does
not support digitally signed jar files. It uses Microsoft-proprietary
single-platform cab files instead. However, recent versions can deal with unsigned
jar files. With the Oracle Java Plug-in, IE (Internet Explorer)
can also deal with Oracle-style signed jars.
- If you use the -jar option, java.exe ignores the classpath. It will only look in that
jar.
- Beginning with JDK 1.2.2 it is no longer
possible to use a Jar file in which some classes of a package are signed and others
are unsigned or signed by a different signer. See signed Applets.
Building Jar Files
You can use GenJar,
Ant,
Gradle or
Maven.
You can create or read jar files with the
java.util.zip classes, or with Oracle’s Jar.exe.
utility.
In theory, you could also use
WinZip version 6.3 or
later to view or delete files. Unfortunately WinZip
there are several problems in using WinZip to create
jar files or to add files to them. I have written the WinZip people several times asking for some simple extensions to
make WinZip suitable for dealing with jar files, but
each time they have refused.
If you are using packages, for jar.exe you must be
in the root directory when using jar.exe to ensure
your package names get properly included because the names you give jar.exe on the command line are the names it will blindly use for
your packages inside the created jar file. You don’t want any names like
J:\com\mindprod\mypackage.MyClass.class
or \com\mindprod\mypackage.MyClass.class or MyClass.class (unless you have no packages). You want names like
com\mindprod\mypackage\MyClass.class which translates to
com.mindprod.mypackage.MyClass.class on the command line.
They have to make sense both as filenames and as fully qualified package/class
names.
If you are not using packages, you must be in the directory where
the class files are when you build your jar. That way the filename MyClass.class will be the same as the classname MyClass.class.
Here in how you build a jar file from class files:
See Main-Class for details on how to create
the main.mft file. See jar.exe for another explanation of how to use it. You create a
main.mft file to help generate an /META-INF/MANIFEST.MF member. You don’t create the /META-INF/MANIFEST.MF directly.
Starting in Java version 1.5, you can super-compress
jar files using pack200.exe. This will optionally remove debug
information and compress the jar as a whole.
Which Classes to Include
Here are some strategies to decide which classes to include in your jar file:
- GenJar. This is fully automatic. GenJar chases dependencies and dependencies of dependencies to find
all the classes. It has two disadvanatages.
- It can include classes that might in theory be used, but in practice would never be used.
- GenJar often fails without explanation. There is nothing you can do to make it work.
- Jet. Create a jar of some of the classes needed. Jet will tell you the classes you left out. The problem with this
method is Jet is quite expensive. This too will include some classes referenced but never actually used.
- Build and Prune.
Build a jar with every class in it that might remotely be used.
Use the java.exe -verbose:class to display
each class as it is loaded. Exercise all the features of the program. Build a new jar with just the
classes that got loaded.
- Use Gradle or
Maven. It is up to you to decide which packages each package needs. Gradle or Maven will then include every single
class. This adds many classes not needed.
- Trial and Error.
This technique is very slow. Build a jar with the classes you think are needed. Run the jar. It will abort when it tries to load
a class not included. Rebuild that jar with that class included. Repeat.
Someone should write a utility that prunes a Jar file of classes never referenced, and produces a list of classes referenced but not present.
This could be used as a final polishing stage in any jar-building technique.
Executing Jar Files
One of the most useful associations to set up is to make *.jar files executable with
java.exe (see below for details how). Then you can just type the name of the jar on the command line to start it executing.
After you have built the
Main-Class entry and set up an association of the *.jar extension to
C:\Program Files\java\jre1.8.0_131\bin\java.exe, all you need to do to run the jar is:
converter.jar
or java.exe -jar converter.jar
Watch out. Java install sets the association back to
javaw.exe, no console! If you get unhandled
Exceptions, you will never
find out about the errors, stack dumps or any other error messages!
To run the jar in an Applet, see Applet for some sample HTML (Hypertext Markup Language) or see
on doing it.
Making Jar Files Double Clickable
In XP, W2003, Vista, W2008, W7-32, W7-64, W8-32, W8-64, W2012, W10-32 and W10-64 you can use the method shown below:.
- Download Johann Löfflmann’s Jarfix.exe.
Run
jarfix.exe
if you want to hook up your 32-bit JRE or
jarfix.exe /64
if you want to hook up your 64-bit JRE. It says on does not
work on W10-32 and W10-64, but it does.
- This will invoke
C:\Program Files\java\jre1.8.0_131\bin\javaw.exe when you run someapp.jar
or double click the someapp.jar file.
- This is Oracle’s official way of doing things — throw away all the console output. I find this
idiotic. You want the output. You want the error messages. You want to invoke
C:\Program Files\java\jre1.8.0_131\bin\java.exe instead.
- To fix the problem, invoke regedit.exe at a run-as-administrator prompt.
Look for:
[HKEY_CLASSES_ROOT\jarfile\shell\open\command]
"C:\Program Files\Java\jre1.8.0_131\bin\javaw.exe" -jar "%1" %*
and change it to:
[HKEY_CLASSES_ROOT\jarfile\shell\open\command]
"C:\Program Files\Java\jre1.8.0_131\bin\java.exe" -jar "%1" %*
- Alternatively, you might configure a custom jarfix.ini file that uses
java.exe in place of javaw.exe with the /c option.
- You also need a config file if your JRE is not on C: or if you have multiple JREs.
The loeffliman.net
website gives instructions on composing an ini file.
You can also use REGEDIT to patch the generated registry entry manually under run-as-administrator.
There are lots of other methods people have recommended, but this is the only one I found that works.
The associations for *.jar and *.jnlp are fragile. They mysteriously change to obsolete versions, or javaw.exe version without a console or even unrelated programs like Winzip.exe. Using the java.exe -jar
myjar.jar syntax in your bat/btm files rather is more robust than myjar.jar. It works even when the associations are
corrupted.
The Manifest
The manifest is a member file inside a JAR file describing the contents of the JAR archive. It
always has the name /META-INF/MANIFEST.MF.
A Oracle signed version is more complex in that it also contains a hash for each member
put here by jarsigner. Manifest-Version: 1.0
Created-By: 1.4.0 (Sun Microsystems Inc.)
Main-Class: com.mindprod.bio.Biorhythms
Name: com/mindprod/bio/Biorhythms.class
SHA1-Digest: ueEw1mJ4aOXT9vmosR0nM/eUt6Y=
Name: com/mindprod/bio/SelectableDate.class
SHA1-Digest: 8HylCo90The8D1mBuYEEOFQDUsY=
The specification document is very loose about the format of a manifest file. Here
are the rules I have gleaned from experimentation:
- It is a simple text file embedded in the jar as member name meta-inf/MANIFEST.MF
- Only forward slashes are used, no \, not even for Windows.
- The jar.exe program automatically generates the
Manifest-Version, Digest-Algorithms, SHA-Digest and
Md5-Digest lines for you inserting them into the
MANIFEST.MF file you manually compose. It will optionally
create the Main-Class line.
It might be wise to review the /META-INF/MANIFEST.MF
member generated by examining the JAR file with WinZip. Unfortunately WinZip
there are several problems in using WinZip to create
jar files or to add files to them.
Starting with Java 7 update 51, you need two extra lines in the manifest:
Application-Name: XXXXX
Permissions: sandbox
Permissions: all-permissions
Sandbox means standard Applet security. full-permissions means full desktop permission.
Manifest Gotchas
- There is no way to put command line arguments destined for java.exe inside the jar in the manifest. However, if you use
JWS, you can put them in the
JNLP file which lives outside the jar. The
reason for this is, by the time the java.exe
JVM (Java Virtual Machine) gets around to looking inside jars, it has already
cast in stone everything it learned from the command line.
- Main-Class gives the fully qualified name
of the class you want executed if the jar is executed without specifying a class.
You must specify it exactly like this
Main-Class: com.mindprod.canadiantax.CanadianTaxCalculator
Note, there is no space before the colon and exactly one afterwards. There
must be a line feed at the end of the line. There is no *.class on the end.
- Be very careful with blank lines. There must be a blank line ahead of each
Name: group and no blank lines within that group. There is no error message if you
make a mistake, just some of your lines may be ignored. Name: statements
don’t necessarily start a fresh group.
- Manifest files don’t have an official comment convention, but you can use
Comment: on the front of a line.
-
Manifest files have about strangest
continuation convention ever invented. No line may be longer than 72 bytes (not
characters), in its UTF8-encoded form. If a value would make the initial line
longer than this, it should be continued on extra lines (each starting with a
single SPACE). Don’t split a name over two lines, e.
Main-Class: com.mindprod.MyProgram
Class-Path: activation.jar axis.jar
commons-discovery.jar
commons-logging.jar
jaxrpc.jar
log4j-1.2.8.jar
mail.jar saaj.jar junit.jar
I suggest putting long names on a line by themselves, with a single space on the
start of the line and using short names to stay away from the 72 limit. Be very
careful with spaces. Don’t add extra ones or remove any. jar.exe is highly sensitive to having its spaces and blank lines
just right. It does not give helpful error messages.
Main-Class
Starting with Java version 1.2,
a jar may made be executable by designating one class in it as the official class
to start when the jar as a whole is executed, e.g. double clicked or executed on the
command java.exe -jar biorhythms.jar
The key is an attribute line in the meta-inf/manifest.inf
manifest member of the form:
Main-Class: com.mindprod.bio.Biorhythms
Of course, the class selected must have a public static
main method. You can use the jar -m option to add
that text to your manifest from a main.mft file containing
text like this:
Main-Class: com.mindprod.bio.Biorhythms
Watch out for extraneous lead/trailing spaces or extraneous trailing
.class. You must have a trailing linefeed or the
main.mft file.
You can also specify the classpath, but you cannot specify command line parameters
or system properties in the manifest.
Manifest Class-Path:
In Java version 1.3 or later
there is an analogous manifest entry to let you control the classpath. It is used to
specify optional jars that will be downloaded only if needed. Normally you would also
place a Jar-index of these files in your main jar to help the loader decide which
ones need to be loaded.
If you have multiple secondary jars, you must specify them in the manifest
Class-Path entry of the master jar. It won’t do you
any good to specify them in the SET CLASSPATH environment parameter or on the java.exe -classpath parameter.
Class-Path: myplace/myjar.jar myplace/other.jar
jardir/
Note how the elements are separated by space, not semicolon or colon as on the
command line.
The elements might be absolute or relative URL
s, but I have not done experiments or found any documentation that describes what
they are relative to. I presume the main jar. It could be the code base of the root
jar file. It could be the CWD (Current Working Directory). If you figure it out,
please let me know.
According to Oracle’s JWS (Java Web Start) FAQ (Frequently Asked Questions), in
Java version 1.5, Java Web Start still does not
support Class-Path. There was a report that up until Java version 1.5,
java.exe too ignored this entry, however, there is another
report it has always worked fine. Class-Path is tricky to
use, possibly leading to the erroneous report. Note the list is space-separated, not
semicolon-separated as in the SET CLASSPATH=C:\;. Note also
that only relative directories and jar names are permitted using / not \. They are relative to the
containing jar. You cannot use C:\. Note also that directory
names need to terminate (but not begin) with a /. This is because Class-Path has to be platform-independent.
Note that jars always ignore the SET classpath and even
the command line classpath. These other two classpaths
are in no way merged with the manifest Class-Path.
If you use -jar on the
java.exe command line, java.exe will quietly ignore the set environment classpath and
any -classpath or -cp command
line options. What are you to do if you have additional jars to include?
- Copy them to the ext directory
- Mention them in the Class-Path: manifest entry. If you
mention them in the manifest, you must specify the jars in relative
URL form
e.g. myplace/myjar.jar and you must separate them by
spaces, not the usual Windows semicolons or Linux colons. You may only use relative
URL
s, so drive letters are not permitted. The jar Class-Path will also be used for
Applets.
- In JDK version 1.4.2+ Mention
these jars in a manifest extension list and they will be downloaded if needed, e.
g.
Extension-List: activation mail
activation-Extension-Name: javax.activation
activation-Implementation-URL: http://abc.com/activation.jar
mail-Extension-Name: javax.mail
mail-Implementation-URL: http://abc.com/mail.jar
- When Java goes searching for classes, it recursively searches the tree of jars
mentioned in the various Class-Path entries in the already
included jars. So you could create a dummy jar whose sole purpose was to provide a
list of other jars to search.
Writing To Jars
To write or update the Jar file, normally you
use the jar.exe utility. Since jars are just
zip files with extra members, you can also use ZIP utilities such as PKZIP and
WinZip.
You can also read and write the jar files from Java with the ZipEntry, ZipException, ZipFile, ZipInputStream and ZipOutputStream classes. While a jar is in use, some
OS (Operating System)
’s may lock it, so don’t count on being able to update jars on the fly
when you are executing classes from them.
Gotchas
It is easy to forget to include everything you need to make a jar totally self
contained. Sometimes jar will work on your machine because all the classes are
otherwise available. However, they won’t work on your client’s machine.
This is such a hassle I have written an entire separate essay on dependencies, how to make sure you include everything
you need in your jar — your classes, all the classes they use and all the
classes they in turn use.
You have a similar problem with packing zip files of classes and source.
When you recompile, naturally this does not magically update all the jars in the
world. Similarly when you build a jar, jar.exe will happily
include out of date class files that really should have been recompiled. Make sure
everything, including classes from other packages have been freshly compiled before
building your jar. Here is my plan for preparing a distribution jar:
- Delete all class files in all vaguely related packages to ensure all are
recompiled with official -targets and that all class
files match the current source.
- Recompile the class you are planning to distribute. That will force a recompile
of classes it uses in other packages. By looking all over for class files you will
see what the dependencies are.
- Recompile and rejar the other packages to incorporate any of the distributed
classes.
- When you are debugging, it is often nice not to use jars.
Then, so long as a class is on the classpath it will be found. You don’t have
to keep careful track of the classes you use to put in the jar until your program
is stable.
Sealing
A package within a jar file can be optionally sealed,
which means that all classes defined in that package must be archived in the same jar
file. You might want to seal a package to prevent tampering, or to prevent accidental
use of classes outside the original set.
To seal a package, you need to add a Name header for the package to your manifest,
followed by a Sealed header, like this:
Name: com/mindprod/myPackage/
Sealed: true
Nesting
The member files in a zip file can be accessed
individually, just like the files in a jar file (a species of zip file). However,
when one zip is contained within another zip, you can only access the contained zip
file itself, not its individual members. You would need to expand it to disk
somewhere before accessing its members.
There are three approaches to the problem:
- Put all members in the same jar/zip.
- Use several individual jar files and arrange to have them on the path.
- Use a JWS installer class to unpack a nested jar into
individual jars.
Jars on the Mac
You create jars on the Mac with the Jar Bundler, (not jar.exe). It creates and includes an XML (extensible Markup Language)
file called Info.plist that behaves something like a JNLP (Java Network Launching Protocol)
file does for a Java Web Start App.
Learning More
Oracle’s Javadoc on
JarFile class : available:
Oracle’s Javadoc on
JarEntry class : available:
Oracle’s Javadoc on
JarInputStream class : available:
Oracle’s Javadoc on
JarOutputStream class : available:
Oracle’s Javadoc on
Pack200 class : available: