bobbyrne01
bobbyrne01

Reputation: 6745

Best approach when packaging a .jar which has dependencies

I've been working on a Java project and managing it using Maven.
The project itself has a number of third party dependencies e.g Box2d, OpenGL ..
When I run mvn package the project's custom source code is packed into a .jar and all it's dependencies are placed in a folder beside the .jar called lib.
A bin folder is also created with a startup script for Windows and *nix platforms. (The assembly descriptor is below).

I'm wondering is this the best way to package this Java based application? Does it lend well for public consuption?
Or would a single, uber.jar be better? Which contains all dependencies in a 1 file.

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}/${project.artifactId}</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>/**</include>
            </includes>
            <excludes>
                <exclude>bin/*</exclude>
            </excludes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/${project.artifactId}/bin</directory>
            <lineEnding>keep</lineEnding>
            <useDefaultExcludes>true</useDefaultExcludes>
            <outputDirectory>bin</outputDirectory>
            <includes>
                <include>*</include>
            </includes>
            <fileMode>755</fileMode>
        </fileSet>
    </fileSets>
</assembly>

Upvotes: 1

Views: 153

Answers (1)

Stephen C
Stephen C

Reputation: 718788

There are 3 common approaches:

  1. Create an uber-jar that contains all of the dependent classes and resources.

  2. Create an executable jar and use the Class-Path manifest attribute to specify a location of the dependent jars.

  3. Create a wrapper script where you specify the location of the dependent jars via a CLASSPATH environment variable or a -cp argument.

(There are other more complicated approaches too ... but I won't go into them here.)

Each approach has advantages and disadvantages.

  • With an uber-jar, it is difficult for the user (deployer, administrator) to use alternate versions of dependencies. (This can be a license requirement of the dependencies!!)

  • With a Class-Path manifest attribute, there is a degree of fragility. If the primary jar OR the dependent jars are not installed in the expected place, then the application won't work. Fixing a broken / inappropriate manifest is fiddly.

  • With the wrapper script approach (and possibly the manifest approach too), you are likely to need different scripts (or attributes) for different platforms.

But as you can see, there is no universal "best approach". (And if someone tells you otherwise, they are making unwarranted assumptions!)

Upvotes: 1

Related Questions