How to install a jar locally in Maven

This topic is probably trivial to Maven veterans however, to people getting started, it is pretty important. As you probably already know if you got here from Googling, Maven is a neat build tool for Java that goes out and downloads all your jar dependencies for you. For example, if you need to use the apache commons lang package, you specify the dependency in your pom.xml Maven will download it for you. Under the hood, what is happening is that Maven will first check your local package repository, located in a directory called .m2 in your home directory, and if it cannot find the package there, it will check remote repositories.

This approach is great for Maven distributed packages and the most commonly used ones are available. If you happen to need to use a package that is not available though, then you will have to install it locally in order for Maven to build your applications with it. This situation happened to me when my work got a license for a new DBMS that had a closed source driver.

Installing a jar is relevantly painless. Simply use the install:install-file goal. Your command should look similar to the one below.

mvn install:install-file -Dfile=closed-source-driver.jar -DgroupId=com.closed-source -DartifactId=com.closed-source.driver -Dversion=1.0 -Dpackaging=jar

Once you have installed the jar, you can now include it as a dependency in any of your projects. Based on the example above, the dependency tag in your pom.xml should look like the following.

<dependency>
<groupId>com.closed-source</groupId>
<artifactId>com.closed-source.driver</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>

Building Self Contained Executable Jars - 2 ways

Building an executable jar file is generally pretty simple if you do not want to package any library jars files with in it. You simply have to insert a Main-Class entry into the manifest file that specifies which class has the main method that you want to execute. That should be sufficient for small Java applications where you do not need to use a jarred library however once you need to use one, problems arise.

One approach is to simple just put your external jars in your classpath however, that is only really acceptable if you are not really deploying your application anywhere. Plus having to push support jar files and update classpaths is a pain. A much preferable approach is you wrap everything up into a single jar file.

Now the Java class loader does not know how to load classes that are in a jar inside another jar which means just manipulating the manifest file will not be enough. Fortunately, there is a nifty utility called one-jar that helps us build these self contained executable jar files. Here I am going to show you 2 ways to use it, one using Maven and one using Ant.

Way 1: Maven
Using Maven is by far the easiest approach. You need to add the following to your pom.xml

</plugins>
  <plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
      <execution>
      <configuration>
        <mainClass>com.chrisjordan.examples.HelloWorld</mainClass>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
      </execution>
    </executions>
  </plugin>
</plugins>

<pluginRepository>
  <id>onejar-maven-plugin.googlecode.com</id>
  <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>

This Maven extension will literally package all the jar dependencies along with your code into a single executable jar file. Simple use the maven goal install or package to generate it.
mvn install
mvn package

Way 2: Ant
Ant is still a really popular build tool but in order to use one-jar, it requires a little more work.

Step 1: Download one-jar

Step 2: Expand it some where that you can reference easily. It is probably the best if you expand it in your project directory since if you are working in a team and are committing your code to a repository, it will need to be there so others can use it without having to think about it.

Step 3: Create a task in your build.xml file similar to the one below

<property name="one-jar.dist.dir" value="one-jar-ant"/>
<import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />
<target name="jar" depends="clean, build, tests">
  <!-- Construct the One-JAR file -->
  <one-jar destfile="${target.dir}/hello-world.jar">
    <manifest>
      <attribute name="One-Jar-Main-Class" value="com.chrisjordan.examples.HelloWorld" />
    </manifest>
    <main>
      <fileset dir="${build.main.dir}"/>
    </main>
    <lib>
      <fileset dir="${target.dir}/lib" includes="*.jar"/>
    </lib>
    <fileset dir="${build.main.res}" includes="**"/>
  </one-jar>
</target>

So as you can see from the above task, there are some gotchas with that using one-jar in ant. You are responsible for the downloading the one-jar package and expanding it in a directory that you reference from your build.xml. As well, you have to specify the jars and property files that you want packaged up.

Now to build your executable jar, you simple have to call ant with the one-jar task you created