0

I'm writing a short application that opens a .jar file, runs a few transforms on its contents, then wraps it up as a .jar file again. I'm using the approach from How to use JarOutputStream to create a JAR file? to create the new jar file and it's working with the exception that it's creating a file hierarchy in new jar file that stretches all the way back to my computer's root.

It's perfectly logical that this is happening since I'm passing the process the target directory as a path from the computer root. What I can't find is any other way of communicating the context that process needs to be able to find my target folder. How do I set the context from which I want the .jar file to be created?

To clarify:

I've rewritten the Run method of the solution linked above to accept two parameters: a string defining the name and location of the output jar file and a string defining the location of the folder I want compressed, like so:

public void run(String output, String inputDirectory) throws IOException
{
  JarOutputStream target = new JarOutputStream(new FileOutputStream(output));     
  add(new File(inputDirectory), target, inputDirectory.length());
  target.close();
}

Two sample values that I hand off to the method would be: C:/temp/964ca469-5f7b-4c56-8b5a-72b4c1c851e0/help.jar and C:/temp/964ca469-5f7b-4c56-8b5a-72b4c1c851e0/out/

I want the structure of my .jar file to have its root at the forward slash following "out", but instead the .jar file's hierarchy is:

C:
 |-Temp
     |-964ca469-5f7b-4c56-8b5a-72b4c1c851e0
                                          |-out
                                             |-{content}

I've tried passing the length of the string preceding the actual content to the Add method and paring it off before adding the JarEntry, but that just gets me an out of index error, which makes perfect sense because I'm just frikkin' groping.

There must be a way of setting the JarEntry class to a specific point in a folder hierarchy before adding a file, or some other means of doing the same thing, but I canna find it so far.

Thanks.

Community
  • 1
  • 1
jrhooker
  • 1,373
  • 2
  • 11
  • 14
  • 1
    Why don't you use the [zip filesystem provider](http://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html) instead? – fge Mar 18 '14 at 23:39
  • Main reason would be that I'm a complete Java noob. I'll try it, but I would like to understand what I'm doing wrong here just from a self-improvement standpoint; I think this might be coming up a lot over the next few months. – jrhooker Mar 19 '14 at 15:16
  • 1
    Well, it is all the more a reason to use the new interface if you are a beginner, it is much easier to use ;) – fge Mar 19 '14 at 15:17

2 Answers2

0

There is no 'root context' in a JAR file. What the files and paths are is completely dependent on what name(s) you put into the JarEntries.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Hmmmmm. I'm mostly an XSLT hack, where context is everything, so I'm likely just stalling on the concept here. Here's what I don't understand about your answer: I'm using the full path of the resource to bring it to the attention of the Jar process; if I don't do that, then I need some way of bringing the Jar process to the resource instead. Am I making my problem clear here? Right now I'm ending up with a file structure in my Jar file that stretches all the way back to my computer's root; what I want is a filesystem that starts at the level of the last directory that I give to the process. – jrhooker Mar 19 '14 at 04:20
0

Never figured out how to do it with Jar file creation, but as fge suggested the zip filesystem provider was indeed easier to work with. I used this in my main method:

CreateJarPackage zipper = new CreateJarPackage();

    System.out.println(baseline + unique_directory  + "/" + out_jar_file);
    System.out.println(baseline + unique_directory + "/out/");
    System.out.println(baseline.length() + unique_directory.length() + 5);

    try {
        zipper.addZipFiles(baseline + unique_directory + "/" + out_jar_file, baseline + unique_directory + "/out/", baseline.length() + unique_directory.length() + 5);
    } catch (Throwable e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    File folder = new File(baseline + unique_directory + "/out/");
    File[] listOfFiles = folder.listFiles();

    for (int i = 0; i < listOfFiles.length; i++) {
        if (listOfFiles[i].isDirectory()) {

            try {
                zipper.addZipFiles(baseline + unique_directory  + "/" + out_jar_file, listOfFiles[i].toString(), baseline.length() + unique_directory.length() + 5);
            } catch (Throwable e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

To call this:

import java.io.File;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;

public class FinalZipCreator {
public static void processList(URI uri, Map<String, String> env, String path)
        throws Throwable {
    try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        int index = path.length();
        for (int i = 0; i < listOfFiles.length; i++) {
            if (listOfFiles[i].isFile()) {
                Path externalTxtFile =Paths.get(listOfFiles[i].toString());
                Path pathInZipfile = zipfs.getPath(listOfFiles[i]
                        .toString().substring(index));
                // copy a file into the zip file
                Files.copy(externalTxtFile, pathInZipfile,
                        StandardCopyOption.REPLACE_EXISTING);
            } else if (listOfFiles[i].isDirectory()) {
                Path externalTxtFile = Paths.get(listOfFiles[i].toString());
                Path pathInZipfile = zipfs.getPath(listOfFiles[i]
                        .toString().substring(index));
                // copy a file into the zip file
                Files.copy(externalTxtFile, pathInZipfile,
                        StandardCopyOption.REPLACE_EXISTING);
                File folder2 = new File(listOfFiles[i].toString());
                File[] listOfFiles2 = folder2.listFiles();
                int index2 = listOfFiles[i].toString().length();
                for (int e = 0; e < listOfFiles2.length; e++) {
                    if (listOfFiles2[i].isFile()) {
                        Path externalTxtFile2 = Paths.get(listOfFiles2[e].toString());
                        Path pathInZipfile2 = zipfs.getPath(listOfFiles2[e]
                                .toString().substring(index2));
                        // copy a file into the zip file
                        Files.copy(externalTxtFile2, pathInZipfile2,
                                StandardCopyOption.REPLACE_EXISTING);
                    }
            }
        }

    }}

}

}

There's likely a zillion better ways of doing it, but it worked. Thanks for the help.

As a side note, it's the equivalent of the "pathInZipFile" function that I could never locate in the Jar creator.

jrhooker
  • 1,373
  • 2
  • 11
  • 14