Saturday, November 29, 2014

Manipulating JARs, WARs, and EARs on the Command Line

Although Java IDEs and numerous graphical tools make it easier than ever to view and manipulate the contents of Java archive (JAR, WAR, and EAR) files, there are times when I prefer to use the command-line jar command to accomplish these tasks. This is particularly true when I have to do something repeatedly or when I am doing it as part of a script. In this post, I look at use of the jar command to create, view, and manipulate Java archive files.

JAR files will be used primarily in this post, but the commands I demonstrate on .jar files work consistently with .war and .ear files. It's also worth keeping in mind that the JAR format is based on the ZIP format and so the numerous tools available for working with ZIP files can be applied to JAR, WAR, and EAR files. It's also worth keeping in mind that the jar options tend to mirror tar's options.

For my examples, I want to jar up and work with some .class files. The next screen snapshot demonstrates compiling some Java source code files (.java files) into .class files. The actual source of these files is insignificant to this discussion and is not shown here. I have shown compiling these without an IDE to be consistent with using command-line tools in this post.

Preparing the Files to Be Used in the jar Examples

The next screen snapshot shows my .class files have been compiled and are ready to be included in a JAR.

Creating a JAR File

The "c" option provided to the jar command instructs it to create an archive. I like to use the "v" (verbose) and "f" (filename) options with all jar commands that I run so that the output will be verbose (to help see that something is happening and that it's the correct thing that's happening) and so that the applicable JAR/WAR/EAR filename can be provided as part of the command rather than input or output depending on standard input and standard output. In the case of creating a JAR file, the options "cvf" will create JAR file (c) with specified name (f) and print out verbose output (v) regarding this creation.

The next screen snapshot demonstrates the simplest use of jar cvf. I have changed my current directory to the "classes" directory so that creating the JAR is as simple as running jar cvf * or jar cvf . and all files in the current directory and all subdirectories and files in subdirectories will be included in the created JAR file. This process is demonstrated in the next screen snapshot.

If I don't want to explicitly change my current directory to the most appropriate directory from which to build the JAR before running jar, I can use the -C option to instruct jar to implicitly do this as part of its creation process. This is demonstrated in the next screen snapshot.

Listing Archive's Contents

Listing (or viewing) the contents of a JAR, WAR, or EAR file is probably the function I perform most with the jar command. I typically use the options "t" (list contents of archive), "v" (verbose), and "f" (filename specified on command line) for this. The next screen snapshot demonstrates running jar tvf MyClasses.jar to view the contents of my generated JAR file.

Extracting Contents of Archive File

It is sometimes desirable to extract one or many of the files contained in an archive file to work on or view the contents of these individual files. This is done using jar "x" (for extract) option. The next screen snapshot demonstrates using jar xvf MyClasses.jar to extract all the contents of that JAR file. Note that the original JAR file is left intact, but its contents are all now available directly as well.

I often only need to view or work with one or two files of the archive file. Although I could definitely extract all of them as shown in the last example and only edit those I need to edit, I prefer to extract only the files I need if the number of them is small. This is easily done with the same jar xvf command. By specifying the fully qualified files to extract explicitly after the archive file's name in the command, I can instruct to only extract those specific files. This is advantageous because I don't fill my directory up with files I don't care about and I don't need to worry about cleaning up as much when I'm done. The next screen snapshot demonstrates running jar xvf MyClasses.jar dustin/examples/jar/GrandParent.class to extract only that single class definition for GrandParent rather than extracting all the files in that JAR.

Updating an Archive File

Previous examples have demonstrated providing the jar command with "c" to create an archive, "t" to list an archive's contents, and "x" to extract an archive's contents. Another commonly performed function is to update an existing archive's contents and this is accomplished with jar's "u" option. The next screen snapshot demonstrates creating a text file (in DOS with the copy con command) called tempfile.txt and then using jar uvf MyClasses.jar tempfile.txt to update the MyClasses.jar and add tempfile.txt to that JAR.

If I want to update a file in an existing archive, I can extract that file using jar xvf, modify the file as desired, and place t back in the original JAR with the jar uvf command. The new file will overwrite the pre-existing one of the same name. This is simulated in the next screen snapshot.

Deleting an Entry from Archive File

It is perhaps a little surprising to see no option for deleting entries from a Java archive file when reading the jar man page, the Oracle tools description of jar, or the Java Tutorials coverage of jar. One way to accomplish this is to extract the contents of a JAR, remove the files that are no longer desired, and re-create the JAR from the directories with those files removed. However, a much easier approach is to simply take advantage of the Java archiving being based on ZIP and use ZIP-based tools' deletion capabilities.

The next screen snapshot demonstrates using 7-Zip (on Windows) to delete tempfile.txt from MyClasses.jar by running the command 7z d MyClasses.jar tempfile.txt. Note that the same thing can be accomplished in Linux with zip -d MyClasses.jar tempfile.txt. Other ZIP-supporting tools have their own options.

WAR and EAR Files

All of the examples in this post have been against JAR files, but these examples work with WAR and EAR files. As a very simplistic example of this, the next screen snapshot demonstrates using jar uvf to update a WAR file with a new web descriptor. The content of the actual files involved do not matter for purposes of this illustration. The important observation to make is that a WAR file can be manipulated in the exact same manner as a JAR file. This also applies to EAR files.

Other jar Operations and Options

In this post, I focused on the "CRUD" operations (Create/Read/Update/Delete) and extraction that can be performed from the command-line on Java archive files. I typically used the applicable "CRUD" operation command ("c", "t", "u") or extraction command ("x") used in conjunction with the common options "v" (verbose) and "f" (Java archive file name explicitly specified on command line). The jar command supports operations other than these such as "M" (controlling Manifest file creation) and "0" (controlling compression). I also did not demonstrate using "i" to generate index information for a Java archive.

Additional Resources on Working with Java Archives

I referenced these previously, but summarize them here for convenience.

Conclusion

The jar command is relatively easy to use and can be the quickest approach for creating, viewing, and modifying Java archive files contents in certain cases. Familiarity with this command-line tool can pay off from time to time for the Java developer, especially when working on a highly repetitive task or one that involves scripting. IDEs and tools (especially build tools) can help a lot with Java archive file manipulation, but sometimes the "overhead" of these is much greater than what is required when using jar from the command line.

No comments: