3 minute read

Imagine you need to use a Java library that is not managed and published using the Apache Maven ecosystem. Thus, you end up downloading a JAR file and need to integrate this JAR reliably into your project infrastructure, which of course uses Maven.

The best way of doing this is turning the JAR file into a Maven artifact and referencing it in the project using standard Maven dependency management. Let’s say we downloaded a file called important-library-1.0.0.jar. We first need to somehow determine the Maven coordinates of this file. We could inspect the file, looking for the most specific common package name, using it as groupId, artifactId and version could be based on the JAR file’s name. Note that these are to a large extent arbitrary (with some exceptions, as will be seen later), but it is good to make them at least somewhat deterministic.

Using Maven Dependency with System Scope

You could put such an artifact among dependencies in your pom.xml, give it a system scope and provide a systemPath parameter specifying path to the file. Of course, you would want to use a relative path so that the build configuration works on other stations. The dependency would thus look something like this:

<dependency>
  <groupId>org.example</groupId>
  <artifactId>important-library</artifactId>
  <version>1.0.0</version>
  <scope>system</scope>
  <systemPath>${project.baseDir}/libs/important-library-1.0.0.jar</systemPath>
</dependency>

This strategy is fine if you plan to use the dependency only in a single project, and you do not mind putting the library into SCM.

Deploying the Artifact to a Remote Maven Repository

Many organizations maintain their own Maven repository, either because they do not want to undergo the publication process of Maven Central, or because they have artifacts that they do not want to share with everyone. It is possible to use a repository manager such as Sonatype Nexus, but if one just needs to get something quickly up and running, it is sufficient to just use a directory accessible by a Web server (on Debian with Apache2, this could be a directory in /var/www). To publish into such a repository, the Apache Maven Deploy Plugin has to be used.

Normally, one would declare a Maven Wagon plugin in the project’s pom.xml and use the Maven Deploy Plugin in cooperation with Wagon to deploy the artifact (Wagon and its providers take care of the actual data transfer). This gets trickier when we do not have any pom.xml.

Maven guide on deploying JARs to remote repository mentions that one needs to have a corresponding Wagon provider in ${maven.home}/lib. However, by default, Maven comes with only the file and http Wagon providers. If we want to deploy using SCP (which is probably the most common way for a remote repository), Maven will complain because it does not have a suitable Wagon provider for this. Therefore, we need to download the corresponding provider JAR’s and manually place them into Maven home.

The following is a complete guide to setting up and deploying JAR files to a remote repository using Maven and Wagon over SCP:

  • Find out where your ${maven.home} is. It is usually the installation directory of Maven. Easiest way is to run mvn -v and look for the home directory in the output.
Output of the 'mvn -v' command.
  • Download the Wagon SSH External and Wagon SSH Common JARs from Maven Central and place them in ${maven.home}/lib. You should download version matching the version of the Wagon providers already present in ${maven.home}/lib.
  • Set up SCP connection to your target server using SSH keys (the deployment does not work with username/password combination).
  • Put configuration of the SCP connection into ${user.home}/.m2/settings.xml. The configuration may look something like:
<server>
    <id>server-id</id>
    <username>my-username</username>
    <privateKey>${user.home}/.ssh/id_rsa</privateKey>
</server>
  • Now you can deploy the artifact using Apache Maven Deploy Plugin:
mvn deploy:deploy-file -Dfile=important-library-1.0.0.jar -DgroupId=org.example -DartifactId=important-library -Dversion=1.0.0 -Dpackaging=jar -DrepositoryId=server-id -Durl=scpexe://my-remote-server.com:/path/to/maven/repository

Some additional notes:

  • The repositoryId parameter in the deployment call must match the server id in settings.xml.
  • We assume SCP is installed on the calling system. Wagon SSH External will use this existing SCP installation.
  • The JAR file’s name should correspond to the artifactId and version.

What Does Not Work?

You may be tempted to skip the hassle with Wagon, copy the JAR file directly to the server and install it using the Maven Install Plugin. However, this will not work because the Maven Install Plugin does not generate the maven-metadata.xml file and Maven will not be able to use such an artifact.

Conclusion

Using libraries that are distributed outside the Apache Maven ecosystem is possible in multiple ways. But if the library is expected to be used by multiple projects, it makes sense to publish it to a remote repository. This post has provided steps to accomplish this.

Hopefully, someone (maybe me in a couple of months/years) finds this useful.

Categories: ,

Updated: