Bundling JAR dependencies with executable JAR (Übe

2020-07-13 10:35发布

问题:

I'm trying to create an executable jar from the command line. The main class in the JAR has dependencies that i have packaged into another plain JAR file.

I want to package the dependency JAR together with the executable JAR in order to have a single JAR file to ship.

What i have tried so far is the following:

The dependency Hello.class file has the mock code:

public class Hello {
    public String getHello() {
        return "Well hello there!!";
    }
}

I have packaged class file into hello.jar using:

jar cvfM hello.jar Hello.class

The hello.jar content is now:

hello.jar -+- Hello.class

Now i have the main class with the mock code:

public class Main {
    public static void main(String[] args) {
        System.out.println(new Hello().getHello());
    }
}

I then create a manifest file manifest.txt with the following content:

Main-Class: Main
Class-Path: hello.jar

I now create the executable JAR using:

jar cvfm main.jar manifest.txt Main.class hello.jar

The main.jar content is now:

main.jar -+- Main.class
          |
          +- hello.jar
          |
          +- META-INF -+- MANIFEST.MF

Running the executable JAR using:

java -jar main.jar

I get a class loader error for the Hello class dependency. I understand that this is because the class loader looks for hello.jar in the same path as main.jar. So when i put a copy of hello.jar alongside main.jar i am able to run it.

What do i need to do in order to be able to run main.jar with hello.jar inside of it?

I know that you will ask: "why is he trying to do it this way?". I know that ppl mostly use Eclipse, Ant, Maven or other tools to do this. But please just humor me :)

回答1:

Your approach is completely wrong unfortunately. There is no "normal" way to place a jar inside of another jar. So your hello.jar has nothing to do inside of main.jar! The point is the "normal" classloader wont look for jar files inside of jars, hence you get the class not found error. However: if you want desparetly to do that, then google for "OneJar" and go to http://one-jar.sourceforge.net/



回答2:

There's no easy way to do this. That is, you are going to have to write your own classloader if you want to nest jars inside a jar.

There are several products out there that already support this for you. One-Jar is one of them that I've used with a lot of success -- can easily ant script it.

Here is an interesting SO discussion on the whole topic --

Easiest way to merge a release into one JAR file



回答3:

Well, I believe you may be facing a jar generation bug. Check out this link, it might enlight you.

A teaser:

As far as I aware, and based on my own attempts, there's no way to specify a Class-Path that makes the class loader look in embedded jar files. See the preceeding paragraph for a description.

Therefore, you may check one of the following links: classpath-including-jar-within-a-jar, java-easiest-way-to-merge-a-release-into-one-jar-file

Cheers!