tags:

views:

47

answers:

2

Hi
I want to add some compiled classes (.class files) to directories(packages) in current Jar file at runtime
How can I do that?

Thanks

+2  A: 

This cannot be done - To update a Jar file you need to create a new one and overwrite the old one with the new one.

Below is a sample on how you would do this:

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;

public class JarUpdate {
   /**
    * main()
    */
   public static void main(String[] args) throws IOException {
      // Get the jar name and entry name from the command-line.

      String jarName = args[0];
      String fileName = args[1];

      // Create file descriptors for the jar and a temp jar.

      File jarFile = new File(jarName);
      File tempJarFile = new File(jarName + ".tmp");

      // Open the jar file.

      JarFile jar = new JarFile(jarFile);
      System.out.println(jarName + " opened.");

      // Initialize a flag that will indicate that the jar was updated.

      boolean jarUpdated = false;

      try {
         // Create a temp jar file with no manifest. (The manifest will
         // be copied when the entries are copied.)

         Manifest jarManifest = jar.getManifest();
         JarOutputStream tempJar =
            new JarOutputStream(new FileOutputStream(tempJarFile));

         // Allocate a buffer for reading entry data.

         byte[] buffer = new byte[1024];
         int bytesRead;

         try {
            // Open the given file.

            FileInputStream file = new FileInputStream(fileName);

            try {
               // Create a jar entry and add it to the temp jar.

               JarEntry entry = new JarEntry(fileName);
               tempJar.putNextEntry(entry);

               // Read the file and write it to the jar.

               while ((bytesRead = file.read(buffer)) != -1) {
                  tempJar.write(buffer, 0, bytesRead);
               }

               System.out.println(entry.getName() + " added.");
            }
            finally {
               file.close();
            }

            // Loop through the jar entries and add them to the temp jar,
            // skipping the entry that was added to the temp jar already.

            for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
               // Get the next entry.

               JarEntry entry = (JarEntry) entries.nextElement();

               // If the entry has not been added already, add it.

               if (! entry.getName().equals(fileName)) {
                  // Get an input stream for the entry.

                  InputStream entryStream = jar.getInputStream(entry);

                  // Read the entry and write it to the temp jar.

                  tempJar.putNextEntry(entry);

                  while ((bytesRead = entryStream.read(buffer)) != -1) {
                     tempJar.write(buffer, 0, bytesRead);
                  }
               }
            }

            jarUpdated = true;
         }
         catch (Exception ex) {
            System.out.println(ex);

            // Add a stub entry here, so that the jar will close without an
            // exception.

            tempJar.putNextEntry(new JarEntry("stub"));
         }
         finally {
            tempJar.close();
         }
      }
      finally {
         jar.close();
         System.out.println(jarName + " closed.");

         // If the jar was not updated, delete the temp jar file.

         if (! jarUpdated) {
            tempJarFile.delete();
         }
      }

      // If the jar was updated, delete the original jar file and rename the
      // temp jar file to the original name.

      if (jarUpdated) {
         jarFile.delete();
         tempJarFile.renameTo(jarFile);
         System.out.println(jarName + " updated.");
      }
   }
}
Romain Hippeau
But Jar files are zip format and it's possible to add files to zip archives!
Snigger
@Snigger If you use WinZip or 7Zip yes, not in Java.
Romain Hippeau
@Romain Hippeau They are programs too , not?
Snigger
@Snigger: Java's zip support is not as powerful as those programs; reimplementing or extending it to support adding entries to existing archives would probably be quite a lot of work. And it most likely still could not do what you want, nor could WinZip or 7Zip, since the file you want to write to would be locked by the JVM which has been reading classes from it.
Michael Borgwardt
+1  A: 

I'm not quite sure but I don't think it's possible to load classes from a JAR file (let's call it foo.jar), then modify the very same JAR file from which the classes were loaded, add a new class and expect the class to be found by the ClassLoader.

I'd think about refactoring the application itself and make it able to load classes dynamically (using URLClassLoader or any other technique) than trying to force the single JAR behaviour you described.

perdian