Reposted from http://www.javaworld.com/ Article This article introduces how to move from a Java program to move in manifest.mf, so that JAR files can be run directly.
Enable your unrunnable jars to run with the java -jar Command
Shawn Silverman
SummaryThis tip shows how to turn an unrunnable Java Archive (JAR) into a runnable one, without having to directly manipulate manifest files. You learn to develop a short program that enables any JAR to run with the java -jar command or on an operating system Like Windows with Just A Double Click. (1,100 Words; May 10, 2002)
You can easily package an application's entire set of classes and resources into a Java Archive (JAR). In fact, that is one goal of having jar files. Another is to let users easily execute the application stored in the archive. Why then are jar FILES SECOND-CLASS CITIZENS IN THE JAVA UNIVERSE-FUNCTIONING ONLY AS ARCHIVES-WHEN THEY CAN BE FIRST CLASS, RIGHT Alongside Native Executables?
To execute a jar file, you can use the java command's -jar option For example, say you have a runnable jar file called myjar.jar Because the file is runnable, you can execute it like this:.. Java -jar myjar.jar .
Alternatively, the Java Runtime Environment (JRE), when installed on an OS like Microsoft Windows, associates jar files with the JVM so you can double-click on them to run the application. These JARs must be runnable.
The Question IS: How do you make a jar runnable?
The manifest file and the Main-Class entryInside most JARs, a file called MANIFEST.MF is stored in a directory called META-INF. Inside that file, a special entry called Main-Class tells the java -jar command which class to execute.
The problem is that you must properly add this special entry to the manifest file yourself-it must go in a certain place and must have a certain format. However, some of us do not like editing configuration files.Let the API do it for youSince Java 1.2, a package called java.util.jar has let you work with jar files (Note:. It builds on the java.util.zip package). Specifically, the jar package lets you easily manipulate via that special manifest file the MANIFEST CLASS.
Let's Write a Program That Uses This API. First, this Program Must Know About Three Things:
The JAR we wish to make runnable The main class we wish to execute (this class must exist inside the JAR) The name of a new JAR for our output, because we should not simply overwrite files Write the programThe above list will constitute our program's ARGUMENTS. AT THIS POINT, LET'S CHOOSE A SUITABLE NAME for this application. How does makejarrunnable sound?
Check the arguments to mainassume ur main entry point is a standard main (string []) method. We stay first check The program arguments here:
IF (args.length! = 3) {system.out.println ("USAGE: Makejarrunnable" "
"); System.exit (0);
Please pay attention to how the argument list is interpreted, as it is important for the following code The argument order and contents are not set in stone;. However, remember to modify the other code appropriately if you change them.
Access The Jar and ITS Manifest Filefirst, We Must Create Some Objects That Know About Jar and Manifest Files:
// Create The JarinputStream Object, And Get ITS Manifest
JarInputStream jarIn = new JarInputStream (new FileInputStream (args [0])); Manifest manifest = jarIn.getManifest (); if (manifest == null) {// This will happen if no manifest existsmanifest = new Manifest ();}
Set the Main-Class attributeWe put the Main-Class entry in the manifest file's main attributes section. Once we obtain this attribute set from the manifest object, we can set the appropriate main class. However, what if a Main-Class attribute already exists In The Original Jar? This Program Simply Prints A Warning and Exits. Perhaps We Could Add A Command-line Argument Tower Tells The Program To Use The New Value Instead of The Pre-EXISTINE:
Attributes a = manifest.getmainattributes (); string oldmainclass = a.putValue ("main-class", args [1]);
// if an old value exists, tell the user and exit
IF (OldMainClass! = null) {system.out.println ("Warning: Old main-class value is:" OldMainClass); System.exit (1);
Output the new JARWe need to create a new jar file, so we must use the JarOutputStream class Note:. We must ensure we do not use the same file for output as we do for input Alternatively, perhaps the program should consider the case. Where the two jar files area the Same and prompt the user if He Wishes to overwrite the original. ho'ver, i reserve this as an adrise for the reader. on with the code!
System.out.println ("Writing to" args [2] "..."); JaroutputStream Jarout = New JaroutputStream (New FileoutputStream (Args [2]), Manifest);
WE Must Write Everyue from the Input Jar To The Output Jar, So Iteerate Over the Entries: // Create a Read Buffer To Transfer Data from The INPUT
BYTE [] BUF = New byte [4096];
// iperate the entry
Jarentry Entry; while ((entry = jarin.getnextjarentry ())! = Null) {// Exclude the manifest file from the old jar
IF ("meta-inf / manifest.mf" .equals (entry.getname ())).
// write the entry to the output jar
Jarout.putNextentry (entry); int = jarin.read (buf))! = -1) {Jarout.write (buf, 0, read);}
Jarout.closeentry ();
// Flush and close all the streams
Jarout.flush (); jarout.close ();
Jarin.close ();
Complete Program, WE Must Place This Code Inside a Main Method, Inside A Class, And with a suitable set of import statements. The resources section.. The resource.
Usage exampleLet's put this program to use with an example. Suppose you have an application whose main entry point is in a class called HelloRunnableWorld. (This is the full class name.) Also assume that you've created a JAR called myjar.jar, Containing the entire application. Run Makejarrunnable on this Jar File Like SO:
Java makejarrunnable myjar.jar HellorunnableWorld myjar_r.jar
Again, AS Mentioned Earlier, NOTICE How I ORDER The Argument List. If you forget the Order, Just Run this program with no arguments and it will respond with a usage message.
Try to run the java -jar command on myjar.jar and the on myjar_r.jar. Note The Difference! After You'Ve Done That, Explore The Manifest Files (Meta-INF / MANIFEST.MF) in Each Jar. (You CAN) Find Both Jars in The Source Code.)
Here's a suggestion:! Try to make the MakeJarRunnable program into a runnable JAR Run with itRunning a JAR by double-clicking it or using a simple command is always more convenient than having to include it in your classpath and running a specific main class To. help you do this, the JAR specification provides a Main-Class attribute for the JAR's manifest file. The program I present here lets you utilize Java's JAR API to easily manipulate this attribute and make your JARs runnable.
About the authorShawn Silverman is currently a graduate student in the department of electrical and computer engineering at the University of Manitoba in Canada. He started working with Java in mid-1996, and has been using it almost exclusively ever since. His current interests include the simulation of electric fields and fluids, error-correcting codes, and the implementation of nifty GUI (graphical user interface) tricks. Shawn also teaches a third-year software design course in the computer engineering department at his university.
Resources
Download the Source Code and Jars for this Tip: http://www.javaworld.com/javaworld/javatips/javatip127/makejarrunnable.zip
"Java Tip 120: Execute Self-extracting jars," Z. Steve Jin and John D. Mitchell (JavaWorld, November 2001): http://www.javaworld.com/javaworld/javatips/jw-javatip120.html
Jar File Specification: http://java.sun.com/guide/jar/jar.html
Jar-The Java Archive Tool: http://java.sun.com/j2se/1.3/docs/tooldocs/win32/jar.html
View All Previous Java Tips and Submit Your Own: http://www.javaworld.com/javatips/jw-javatips.index.html
Learn Java from the ground up in JavaWorld's Java 101 column: http://www.javaworld.com/javaworld/topicalindex/jw-ti-java101.htmlJava experts answer your toughest Java questions in JavaWorld's Java Q & A column: http: // www .javaworld.com / javaworld / javaqa / javaqa-index.html
Browse the core java section of javaworld's topical index: http://www.javaworld.com/channel_content/jw-core-index.shtml
Stay on top of our tips' n tricks by subscribing to javaworld's free weekly email newsletters: http://www.javaworld.com/subscribe
. Learn the basics of client-side Java in JavaWorld's Java Beginner discussion Core topics include the Java language, the Java Virtual Machine, APIs, and development tools: http://forums.devworld.com/webx?50@@.ee6b804
You'll Find A Wealth of It-Related Articles from Our Sister Publications At IDG.Net
-------------------------------------------------- -----
Import java.io.fileinputstream; import java.io.fileoutputstream; import java.io iexception; import java.util.jar. *;
/ ** * This utility makes a JAR runnable by inserting a Main-Class code> * attribute into the Manifest. * * @Author Shawn Silverman * / public class MakeJarRunnable {public static void main (String [] args "throws oException {if (args.length! = 3) {system.out.println (" usage: makejarrunnable "
// Create The JarinputStream Object, And Get ITS Manifest
JarInputStream jarIn = new JarInputStream (new FileInputStream (args [0])); Manifest manifest = jarIn.getManifest (); if (manifest == null) {// This will happen if there is no Manifestmanifest = new Manifest ();}
Attributes a = manifest.getmainattributes (); string oldmainclass = a.putValue ("main-class", args [1]);
// if there is an old value there, tell the user about it and exit
IF (OldMainClass! = null) {system.out.println ("Warning: Old main-class value is:" OldMainClass); System.exit (1);
System.out.println ("Writing to" args [2] "..."); JaroutputStream Jarout = New JaroutputStream (New FileoutputStream (Args [2]), Manifest);
// Create a Read buffer to be used for transferring data from there
BYTE [] BUF = New byte [4096];
// iperate the entry
Jarentry Entry; while ((entry = jarin.getnextjarentry ())! = Null) {// Exclude the manifest file from the old jar
IF ("meta-inf / manifest.mf" .equals (entry.getname ())).
// Write out the entry to the output jar
Jarout.putNextentry (entry); int = jarin.read (buf))! = -1) {Jarout.write (buf, 0, read);}
Jarout.closeentry ();
// Flush and close all the streams
Jarout.flush (); jarout.close ();
Jarin.close ();}}