14

Possible Duplicate:
Put external library to the JAR?

I have NetBeans 6.8 and I wrote one class which has two libraries (jar-files). Building it, I get a "dist" folder with my project.jar and a "lib" folder which contains the two lib jar files.

How could I get all this in one jar file? (I do not use Maven/Ant or something like this.)

Community
  • 1
  • 1
Tim
  • 13,228
  • 36
  • 108
  • 159

5 Answers5

13

The basic problem is that the current version of Java does not support jars inside jars out of the box.

The recommended solution is to use the Class-Path line in the MANIFEST.MF file inside your jar to point to required libraries (relative paths are allowed) and then deploy all files together and invoking it with "java -jar your.jar"

If you really want to have a "jar-inside-jar" solution, we have used one-jar for several years, but gone away from it since our target JVM worked better with the solution described above.

http://one-jar.sourceforge.net/

I used it with the fatjar plugin in Eclipse. I do not have any experiences with building it into Netbeans, but it is simple to build into an ant script which I believe is what NEtbeans use anyway.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
13

You can create an extra build target in the build.xml file. And use zipfileset and zipgroupfileset to create one big jar e.g.

<target name="YourBigJar" depends="-post-jar">
  <jar destfile="BigJar.jar">
    <zipfileset src="dist/Project1.jar"/>
    <zipfileset src="../OtherProject/dist/project2.jar"/>
    <zipgroupfileset dir="../libs/."/>
  </jar>
</target>
Waverick
  • 1,984
  • 1
  • 11
  • 16
13

I agree with Waverick. The simplest way to do this with NetBeans is to add a custom target to your build.xml. (By the way, by virtue of using NetBeans, you are using Ant, since NetBeans uses Ant to build your jar file.)

Waverick's Ant target seems to be designed to merge the compiled code from a different NetBeans project into the current project's jar file. My targets below do exactly what you are looking for.

<target name="-unjar-and-copy-lib-jars">
    <unjar dest="${build.classes.dir}">
        <fileset dir="lib">
            <include name="**/*.jar"/>
        </fileset>
        <patternset>
            <exclude name="META-INF/**"/>
            <exclude name="/*"/>
        </patternset>
    </unjar>
</target>

<target depends="init,compile,-pre-pre-jar,-pre-jar,-unjar-and-copy-lib-jars" name="fat-jar">
    <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
    <jar destfile="${dist.jar}">
        <fileset dir="${build.classes.dir}"/>
        <manifest>
            <attribute name="Main-Class" value="${main.class}"/>
        </manifest>
    </jar>
    <echo>To run this application from the command line without Ant, try:</echo>
    <property location="${dist.jar}" name="dist.jar.resolved"/>
    <echo>java -jar "${dist.jar.resolved}"</echo>
</target>

<target depends="clean,fat-jar" name="clean-and-fat-jar"/>
Joshua Born
  • 220
  • 1
  • 8
3

I've found a good article here. But seems it's worth to mention that it is ask for external libraries in dest/lib folder. You can make it that way but normally we have lib folder in the root folder(Or what i have). If it is just change

<zipgroupfileset dir="dist/lib" includes="*.jar"/> to

<zipgroupfileset dir="/lib" includes="*.jar"/>. 

That's all.

chAmi
  • 1,774
  • 3
  • 20
  • 27
1

You can use Java to install the external libraries programmatically using Class.getResourceAsStream() and a FileOutputStream. Libraries will usually go in Java\lib\ext\.

Here's how I approached it:

I placed a copy of all the JAR's I used into a .res subpackage. From there, I can copy them anywhere.

private void installLibraries() {
    new Thread() {

        @Override
        public void run() {
            System.out.println("Checking for libraries");

            File jre = new File(System.getProperty("java.home"));
            File jar = new File(jre, "lib/ext/JAR_NAME.jar");
            //Create more File objects that wrap your JAR's
            try {
                boolean added = false;

                if (!jar.exists()) {
                    copyResource(jar, "JAR_NAME.jar");
                    added = true;
                }
                //Repeat for more JAR's

                if (added) {
                    System.out.println("Libraries installed.");
                } else {
                    System.out.println("Library check complete");

            } catch (IOException ex) {
                System.out.println("Library installation failed.");
                ex.printStackTrace(System.out);
            }
        }

        private void copyResource(File dest, String src) throws IOException {
            System.out.println("Copying resource " + src + " to " + dest);
            InputStream in = THIS_CLASS_NAME.class.getResourceAsStream("/YOUR_PACKAGE/res/" + src);
            dest.getParentFile().mkdirs();
            FileOutputStream out = new FileOutputStream(dest);
            byte[] buffer = new byte[1024];
            int i = 0;
            while ((i = in.read(buffer)) > 0) {
                out.write(buffer, 0, i);
            }
            out.close();
            in.close();
        }
    }.start();
}

Run this method before you do anything else, and you can completely ignore the external JAR files that Netbeans gives you, and just distribute the one. As an additional note, I used this method to install javax.comm, which didn't like being distributed externally. It came with a .dll file and a properties file. These files can be installed using the exact same method, but it's worth noting that the .dll file must be placed in the Java\lib\ directory and properties files go in the Java\lib\ directory (not in the \ext folder).

gobernador
  • 5,659
  • 3
  • 32
  • 51