One of the strongest points of Maven is that it automatically manages project dependencies. The developer just needs to specify which dependencies and in which version are needed and the Maven takes care of the rest including downloading and storing them at the right location and additionally packaging them into final artifact (e.g. WAR). This is very convenient and almost completely removes a need to hold additional jars in lib/ project subdirectory.
However, there is a small assumption that all required dependencies are available at one or more public repositories. It is usually the case but sometimes you may need to use a jar which is not available there for some reason. Luckily, there are few popular approaches to overcome this problem which are described below.
Adding jar to public Maven repository
Theoretically, the best way would be to add a jar to a public Maven repository. However, if the jar is proprietary, it is usually impossible to get the permission from the company to do so.
Using system dependency
The second method is to add the required dependency with the system scope and additionally provide an absolute path to the a jar file placed somewhere on the local disc:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>evalpostfix</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/evalpostfix-1.0.jar</systemPath>
</dependency>
</dependencies>
The problem with this approach is that this dependency will be completely ignored during packaging and forcing Maven to add it to the final artifact (e.g. WAR) would result in a very clumsy POM file.
Installing jar into local Maven repository
Much better solution is to add the required dependency manually to the local repository using command:
$ mvn install:install-file -Dfile=<path-to-file> \
-DgroupId=<group-id> -DartifactId=<artifact-id> \
-Dversion=<version> -Dpackaging=<packaging>
For example adding external jar evalpostfix-1.0.jar to the local repository could look like this:
$ mvn install:install-file -Dfile=evalpostfix-1.0.jar \
-DgroupId=com.example -DartifactId=evalpostfix \
-Dversion=1.0 -Dpackaging=jar
(...)
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /home/robert/informatyka/softwarecave/infixtopostfix/target/evalpostfix-1.0.jar to /home/robert/.m2/repository/com/example/evalpostfix/1.0/evalpostfix-1.0.jar
[INFO] Installing /tmp/mvninstall2671284263455462989.pom to /home/robert/.m2/repository/com/example/evalpostfix/1.0/evalpostfix-1.0.pom
(...)
Once the dependency is available in the local repository it can be added to POM file like any other dependency:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>evalpostfix</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
This solution is still inconvenient because every new developer working on the project would have to run mvn install:install command on its own workstation.
Using internal Maven repository in a company
One of the best ideas is to setup an internal Maven repository in a company for storing such dependencies. The repository should be available to every developer working on a project though HTTP or other protocol supported by Maven. Of course, the repository server does not have to be available from outside of the company.
The required dependencies should be installed on the repository server using mvn install:install-file command:
$ mvn install:install-file -Dfile=evalpostfix-1.0.jar \
-DgroupId=com.example -DartifactId=evalpostfix \
-Dversion=1.0 -Dpackaging=jar \
-DlocalRepositoryPath=/opt/mvn-repository/
The only difference from the command in the previous section is that it additionally specifies the path on the repository server where the jars and metadata should be stored.
Once it is finished, the dependency can be added to the POM file. Additionally, the location of the new repository server is provided:
<repositories>
<repository>
<id>Internal company repository</id>
<url>http://mvnrepo.company.com/</url>
</repository>
</repositories>
(...)
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>evalpostfix</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
The advantages of this approach should be clearly visible:
- new developers can start building the project without any additional preparation tasks
- no need to send jars though emails, IM or downloading them from the Internet
- reduced or completely removed need for build instructions
- all external jars are managed in a single place
- dependencies and the server can be shared by multiple projects
Using in-project Maven repository
The idea is quite similar to using internal repository server but this time the repository is stored in a directory (e.g. called lib) located in a project root directory. After creating the directory and installing jar files there using mvn install:install-file command, the dependencies and the repository can be referenced from a POM file:
<repositories>
<repository>
<id>Internal company repository</id>
<url>file://${basedir}/lib</url>
</repository>
</repositories>
(...)
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>evalpostfix</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
The created repository including jars, pom files and checksums must be stored in a version control system so that it is available to other developers. The biggest issue with this solution is that it clutters VCS repository with files that such never be placed there (e.g. jars).
Conclusion
Choosing the right solution is not always easy. Personally, I would first try to add the jar into public or at least internal Maven repository in a company. If it is not be possible, I would go for in-project Maven repository and use the other methods as a last resort.


