JARs (and WARs)
Table of Contents
The point of this document is to illustrate some actions surrounding Java ARchives (JARs). Most of this applies also to Web ARchive (WAR) files too.
The JAR is inspired by the long-standing Unix archive ar and its more commonly used incantation tar, originally for tape archive.
Back in the day, libraries of primitive, mostly for C programs, were collected and organized into archives until link time. ar was used to create, examine, maintain and extract them.
You may also be interested in perusing an article on a complete treatment of JARs and Eclipse Build Path.
Unix tar began life as more or less the precursor to what would become known in the Windows world as zip/unzip.
With the arrival of the Java programming language and system, the JAR was born. jar boasts features similar when not identical to tar and makes use of more or less the same arguments as we'll see.
The command we'll be using in a shell or console is:
jar - [ c | x | t ] [ v ] [ f <archive-name> ]
|c||create an archive|
|x||extract from an archive|
|t||list titles (subdirectories, filenames, etc.) in an archive|
|v||be verbose in the information printed to the console|
|f||name of the archive|
You'll see countless illustrations of this command in the examples below.
Step-by-step, here is an example of creating a JAR (this one is done in Eclipse Galileo running on Windows 7). We show how to keep JUnit test code out of the final result.
Here's the project; notice two Eclipse Source Folders: src and test. In the second one, we isolate our JUnit tests. Its packages are identicalt to those in src, however.
(In this example, our project is an Eclipse Dynamic Web Project. In the real world, we'll be making this a WAR for deployment to Tomcat, but it happens to be the project I chose for illustrating the creation of a project JAR with exclusions.)
Right-click on the project and choose Export.... Then click JAR file. Moving step-by-step through the dialogs, this is what you'll see.
Here's the export mechanism' basic offer: JAR up the contents of the project, dvdcatalog.
Expand out the project.
De-click folder test: we don't want to include our JUnit tests when we create the JAR.
Now, name the JAR. According to the note near the top of the dialog, the export wizard's export destination is relative to the workspace. We want to keep this JAR inside our project so the JAR file path will be: project-name/jar-filename:
Then Next. (We're not going to discuss manifest functionality for this example.)
Finally, the JAR is generated and you'll see it at the end of the project in the Package Explorer if you press F5 (or choose Refresh from the File menu).
And, to prove to ourselves that none of the test classes survived the export, let's examine the contents of the JAR. I use the command line; it seems the easiest way to me. (Click on this image to see it full size if you need to.)
Since I haven't done this from the command line, you'll have to go elsewhere to learn that (actually, it's very simple—just as creating a JAR). I'm using Eclipse, the IDE with which I develop code and create web applications. First, we start with a completed Dynamic Web Project such as RichFaceletsTutorial below.
We right-click the project and choose to export the project as a WAR.
We browse to someplace to put this file. Not that we'd usually do this, but we're going to include the source files in this WAR just so they'll be there for up-coming illustrations.
This examines the content of a WAR (or JAR) file without respect to directory hierarchy: each line indicates a file or subdirectory archived in this file.
[email protected]:~/Downloads/war-example> ll total 9017 -rw-r--r-- 1 russ russ 9223667 2011-02-22 10:21 RichFaceletsTutorial.war [email protected]:~/Downloads/war-example> jar -tf RichFaceletsTutorial.war META-INF/MANIFEST.MF META-INF/ WEB-INF/ WEB-INF/classes/ WEB-INF/classes/com/ WEB-INF/classes/com/etretatlogiciels/ WEB-INF/classes/com/etretatlogiciels/facelets/ WEB-INF/classes/com/etretatlogiciels/facelets/HelloBean.java WEB-INF/classes/com/etretatlogiciels/facelets/UserNumberBean.java WEB-INF/classes/com/etretatlogiciels/facelets/HelloBean.class WEB-INF/classes/com/etretatlogiciels/facelets/UserNumberBean.class WEB-INF/faces-config.xml WEB-INF/lib/ WEB-INF/lib/commons-beanutils-1.8.3.jar WEB-INF/lib/commons-codec-1.4.jar WEB-INF/lib/commons-collections-3.2.1.jar WEB-INF/lib/commons-digester-2.1.jar WEB-INF/lib/commons-discovery-0.4.jar WEB-INF/lib/commons-logging-1.1.1.jar WEB-INF/lib/myfaces-api-2.0.3.jar WEB-INF/lib/myfaces-impl-2.0.3.jar WEB-INF/lib/richfaces-api-3.3.3.Final.jar WEB-INF/lib/richfaces-impl-3.3.3.Final.jar WEB-INF/lib/richfaces-ui-3.3.3.Final.jar WEB-INF/lib/jsf-facelets-1.1.15.B1.jar WEB-INF/web.xml footer.xhtml guessnumber.xhtml header.xhtml numberresponse.xhtml resources/ resources/images/ resources/images/java_duke.gif template.xhtml templateClient.xhtml test.jsp
On Linux (in GNOME, Cinnamon, etc.), there's an easier way to examine the contents of a JAR or WAR file. This is to use the GNOME Archive Manager. To do this, simply explore the filesystem using Nemo (the GNOME filesystem explorer), navigate to the JAR (or WAR), right-click it and choose Open with..., then Archive Manager (or Other Application and navigate to find the Archive Manager). This utility has existed since 2001. To do this from the command line:
$ file-roller jar-name &
Here we extract the contents. Since this is a WAR, this is exactly what Tomcat does after you drop this file down under its webapps subdirectory. Here, I added v to the command to extract; otherwise, the command would have completed in relative silence.
[email protected]:~/Downloads/war-example> jar -xvf RichFaceletsTutorial.war inflated: META-INF/MANIFEST.MF created: META-INF/ created: WEB-INF/ created: WEB-INF/classes/ created: WEB-INF/classes/com/ created: WEB-INF/classes/com/etretatlogiciels/ created: WEB-INF/classes/com/etretatlogiciels/facelets/ inflated: WEB-INF/classes/com/etretatlogiciels/facelets/HelloBean.java inflated: WEB-INF/classes/com/etretatlogiciels/facelets/UserNumberBean.java inflated: WEB-INF/classes/com/etretatlogiciels/facelets/HelloBean.class inflated: WEB-INF/classes/com/etretatlogiciels/facelets/UserNumberBean.class inflated: WEB-INF/faces-config.xml created: WEB-INF/lib/ inflated: WEB-INF/lib/commons-beanutils-1.8.3.jar inflated: WEB-INF/lib/commons-codec-1.4.jar inflated: WEB-INF/lib/commons-collections-3.2.1.jar inflated: WEB-INF/lib/commons-digester-2.1.jar inflated: WEB-INF/lib/commons-discovery-0.4.jar inflated: WEB-INF/lib/commons-logging-1.1.1.jar inflated: WEB-INF/lib/myfaces-api-2.0.3.jar inflated: WEB-INF/lib/myfaces-impl-2.0.3.jar inflated: WEB-INF/lib/richfaces-api-3.3.3.Final.jar inflated: WEB-INF/lib/richfaces-impl-3.3.3.Final.jar inflated: WEB-INF/lib/richfaces-ui-3.3.3.Final.jar inflated: WEB-INF/lib/jsf-facelets-1.1.15.B1.jar inflated: WEB-INF/web.xml inflated: footer.xhtml inflated: guessnumber.xhtml inflated: header.xhtml inflated: numberresponse.xhtml created: resources/ created: resources/images/ inflated: resources/images/java_duke.gif inflated: template.xhtml inflated: templateClient.xhtml inflated: test.jsp
Here is an illustration of what's now extracted. First, the directory listing.
[email protected]:~/Downloads/war-example> ll total 9045 -rw-r--r-- 1 russ russ 564 2011-02-16 08:50 footer.xhtml -rw-r--r-- 1 russ russ 1312 2011-02-16 17:14 guessnumber.xhtml -rw-r--r-- 1 russ russ 564 2011-02-16 08:50 header.xhtml drwxr-xr-x 2 russ russ 80 2011-02-16 17:23 META-INF -rw-r--r-- 1 russ russ 770 2011-02-16 18:27 numberresponse.xhtml drwxr-xr-x 3 russ russ 72 2011-02-16 17:11 resources -rw-r--r-- 1 russ russ 9223667 2011-02-22 10:21 RichFaceletsTutorial.war -rw-r--r-- 1 russ russ 775 2011-02-16 08:47 templateClient.xhtml -rw-r--r-- 1 russ russ 805 2011-02-16 08:41 template.xhtml -rw-r--r-- 1 russ russ 741 2011-02-11 16:35 test.jsp drwxr-xr-x 4 russ russ 152 2011-02-16 08:08 WEB-INF
Next, the tree structure.
[email protected]:~/Downloads/war-example> tree . |-- footer.xhtml |-- guessnumber.xhtml |-- header.xhtml |-- META-INF | `-- MANIFEST.MF |-- numberresponse.xhtml |-- resources | `-- images | `-- java_duke.gif |-- RichFaceletsTutorial.war |-- templateClient.xhtml |-- template.xhtml |-- test.jsp `-- WEB-INF |-- classes | `-- com | `-- etretatlogiciels | `-- facelets | |-- HelloBean.class | |-- HelloBean.java | |-- UserNumberBean.class | `-- UserNumberBean.java |-- faces-config.xml |-- lib | |-- commons-beanutils-1.8.3.jar | |-- commons-codec-1.4.jar | |-- commons-collections-3.2.1.jar | |-- commons-digester-2.1.jar | |-- commons-discovery-0.4.jar | |-- commons-logging-1.1.1.jar | |-- jsf-facelets-1.1.15.B1.jar | |-- myfaces-api-2.0.3.jar | |-- myfaces-impl-2.0.3.jar | |-- richfaces-api-3.3.3.Final.jar | |-- richfaces-impl-3.3.3.Final.jar | `-- richfaces-ui-3.3.3.Final.jar `-- web.xml 9 directories, 28 files
Ordinarily, we would not distribute source code to our web application. However, an open-source interface, such as the Apache Software Foundation distributes, might be included in the download to facilitate debugging by the consuming developer:
[email protected]:~/dev/downloads/apache-commons/commons-beanutils-1.8.3>jar -tf commons-beanutils-1.8.3-sources.jar META-INF/ META-INF/MANIFEST.MF org/ org/apache/ org/apache/commons/ org/apache/commons/beanutils/ org/apache/commons/beanutils/converters/ org/apache/commons/beanutils/expression/ org/apache/commons/beanutils/locale/ org/apache/commons/beanutils/locale/converters/ org/apache/commons/collections/ org/apache/commons/beanutils/BasicDynaBean.java org/apache/commons/beanutils/BasicDynaClass.java org/apache/commons/beanutils/BeanAccessLanguageException.java org/apache/commons/beanutils/BeanComparator.java org/apache/commons/beanutils/BeanMap.java ... org/apache/commons/collections/BufferUnderflowException.java org/apache/commons/collections/FastHashMap.java org/apache/commons/collections/package.html overview.html META-INF/LICENSE.txt META-INF/NOTICE.txt
Or, we might and we might well also distribute Javadoc:
[email protected]:~/dev/downloads/apache-commons/commons-beanutils-1.8.3>jar -tf commons-beanutils-1.8.3-javadoc.jar META-INF/ META-INF/MANIFEST.MF org/ org/apache/ org/apache/commons/ org/apache/commons/beanutils/ org/apache/commons/beanutils/class-use/ org/apache/commons/beanutils/converters/ org/apache/commons/beanutils/converters/class-use/ org/apache/commons/beanutils/expression/ org/apache/commons/beanutils/expression/class-use/ org/apache/commons/beanutils/locale/ org/apache/commons/beanutils/locale/class-use/ org/apache/commons/beanutils/locale/converters/ org/apache/commons/beanutils/locale/converters/class-use/ org/apache/commons/collections/ org/apache/commons/collections/class-use/ resources/ src-html/ src-html/org/ src-html/org/apache/ src-html/org/apache/commons/ src-html/org/apache/commons/beanutils/ src-html/org/apache/commons/beanutils/converters/ src-html/org/apache/commons/beanutils/expression/ src-html/org/apache/commons/beanutils/locale/ src-html/org/apache/commons/beanutils/locale/converters/ src-html/org/apache/commons/collections/ allclasses-frame.html allclasses-noframe.html constant-values.html deprecated-list.html help-doc.html index-all.html index.html META-INF/LICENSE.txt META-INF/NOTICE.txt org/apache/commons/beanutils/BasicDynaBean.html org/apache/commons/beanutils/BasicDynaClass.html org/apache/commons/beanutils/BeanAccessLanguageException.html org/apache/commons/beanutils/BeanComparator.html org/apache/commons/beanutils/BeanMap.Entry.html org/apache/commons/beanutils/BeanMap.html org/apache/commons/beanutils/BeanPredicate.html org/apache/commons/beanutils/BeanPropertyValueChangeClosure.html org/apache/commons/beanutils/BeanPropertyValueEqualsPredicate.html org/apache/commons/beanutils/BeanToPropertyValueTransformer.html org/apache/commons/beanutils/BeanUtils.html org/apache/commons/beanutils/BeanUtilsBean.html ... org/apache/commons/collections/FastHashMap.html org/apache/commons/collections/package-frame.html org/apache/commons/collections/package-summary.html org/apache/commons/collections/package-tree.html org/apache/commons/collections/package-use.html overview-frame.html overview-summary.html overview-tree.html package-list resources/inherit.gif serialized-form.html src-html/org/apache/commons/beanutils/BasicDynaBean.html src-html/org/apache/commons/beanutils/BasicDynaClass.html src-html/org/apache/commons/beanutils/BeanAccessLanguageException.html src-html/org/apache/commons/beanutils/BeanComparator.html src-html/org/apache/commons/beanutils/BeanMap.Entry.html src-html/org/apache/commons/beanutils/BeanMap.html ... src-html/org/apache/commons/collections/Buffer.html src-html/org/apache/commons/collections/BufferUnderflowException.html src-html/org/apache/commons/collections/FastHashMap.html stylesheet.css
A runnable JAR is one that contains a main intended for use, probably from the command line, as an application. Runnable JARs are considerably fewer in number, finding a lot fewer applications than library JARs and web applications (WARs) or other, modern applications of bundled Java code.
The point of a runnable JAR is, more or less, to reach the main()
method inside one of the classes, usually from the command line. Before
beginning, however, you must have a class with a
In Eclipse, make a runnable JAR by following these steps:
To run the JAR's main() from the command line, type:
# java -jar project-name.jar
If you were hoping to make a runnable JAR out of your project running your JUnit test, you cannot because there's no main() method. To fix this, create a class whose main simulates what the JUnit test does. Then continue.
For example, your new class' main would create an instance of your JUnit class, call the set-up function (which must be public in your JUnit class), then each test. Then it should call the tear-down.