How to Integrate Commercial Third-Party Artefacts into Your Maven Build
According to a recent survey by ZeroTurnaround’s RebelLabs, Maven is still the leading Java build platform. The current market share distribution, according to RebelLabs is:
- Maven with 64%
- Ant + Ivy with 16.5%
- Gradle with 11%
Yet, at the same time, Maven is often criticised for being a bit obscure and intrusive. Compared to runner-ups Ant and Gradle, Maven allows for only little flexibility with respect to interpretation and thus custom adaptation of the build model. Or as Tim Berglund from Data Stax would put it:
But let’s cut the jokes and have a look at a real-world issue:
Integrating Third-Party Commercial Artefacts
Not all third party artefacts that you would like to depend upon are available for free from Maven Central. Examples for this are commercial JDBC drivers, or the commercial jOOQ editions. There are essentially three ways to integrate such artefacts into your build:
Quick-and-dirty
Often, you only need the commercial dependency for a small test project or demo. You want to be sure that it works when you run it without depending on your local repository setup, or on network connectivity. This is a good use-case for <scope>system</scope>
:
For instance: jOOQ
<dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>${jooq.version}</version> <scope>system</scope> <systemPath>${basedir}/lib/jooq-${jooq.version}.jar</systemPath> </dependency>
For instance: Microsoft SQL JDBC
<dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>sqljdbc4</artifactId> <version>3.0</version> <scope>system</scope> <systemPath>${basedir}/lib/sqljdbc4.jar</systemPath> <!-- Notice that we can still put "optional" on commercial JDBC driver dependencies --> <optional>true</optional> </dependency>
Advantages of this approach
This is really a very easy solution when you want to have a local, self-contained module that is guaranteed to run immediately after checkout from source control, without additional configuration and setup. Don’t forget to check in the libraries into source control first, of course.
Disadvantages of this appraoch
The system dependencies are never transitively inherited. If your module depends on jOOQ this way, your module’s dependencies won’t see the jOOQ API.
Details about system dependencies can be seen in the Maven documentation. Citing from the documentation:
Dependencies with the scope system are always available and are not looked up in repository. They are usually used to tell Maven about dependencies which are provided by the JDK or the VM. Thus, system dependencies are especially useful for resolving dependencies on artifacts which are now provided by the JDK, but where available as separate downloads earlier. Typical example are the JDBC standard extensions or the Java Authentication and Authorization Service (JAAS).
A bit more robust
An approach that might appear to be a bit more robust is to check out the dependencies from your version control system and then “manually” import them to your local repository. This will make them available to your own local build. The following shell scripts show how you can import, for instance, the jOOQ artefacts into your local repository
Windows Batch
@echo off set VERSION=3.4.4 if exist jOOQ-javadoc\jooq-%VERSION%-javadoc.jar ( set JAVADOC_JOOQ=-Djavadoc=jOOQ-javadoc\jooq-%VERSION%-javadoc.jar set JAVADOC_JOOQ_META=-Djavadoc=jOOQ-javadoc\jooq-meta-%VERSION%-javadoc.jar set JAVADOC_JOOQ_CODEGEN=-Djavadoc=jOOQ-javadoc\jooq-codegen-%VERSION%-javadoc.jar set JAVADOC_JOOQ_CODEGEN_MAVEN=-Djavadoc=jOOQ-javadoc\jooq-codegen-maven-%VERSION%-javadoc.jar set JAVADOC_JOOQ_SCALA=-Djavadoc=jOOQ-javadoc\jooq-scala-%VERSION%-javadoc.jar ) if exist jOOQ-src\jooq-%VERSION%-sources.jar ( set SOURCES_JOOQ=-Dsources=jOOQ-src\jooq-%VERSION%-sources.jar set SOURCES_JOOQ_META=-Dsources=jOOQ-src\jooq-meta-%VERSION%-sources.jar set SOURCES_JOOQ_CODEGEN=-Dsources=jOOQ-src\jooq-codegen-%VERSION%-sources.jar set SOURCES_JOOQ_CODEGEN_MAVEN=-Dsources=jOOQ-src\jooq-codegen-maven-%VERSION%-sources.jar set SOURCES_JOOQ_SCALA=-Dsources=jOOQ-src\jooq-scala-%VERSION%-sources.jar ) call mvn install:install-file -Dfile=jOOQ-pom\pom.xml -DgroupId=org.jooq -DartifactId=jooq-parent -Dversion=%VERSION% -Dpackaging=pom call mvn install:install-file -Dfile=jOOQ-lib\jooq-%VERSION%.jar -DgroupId=org.jooq -DartifactId=jooq -Dversion=%VERSION% -Dpackaging=jar %JAVADOC_JOOQ% %SOURCES_JOOQ% -DpomFile=jOOQ-pom\jooq\pom.xml call mvn install:install-file -Dfile=jOOQ-lib\jooq-meta-%VERSION%.jar -DgroupId=org.jooq -DartifactId=jooq-meta -Dversion=%VERSION% -Dpackaging=jar %JAVADOC_JOOQ_META% %SOURCES_JOOQ_META% -DpomFile=jOOQ-pom\jooq-meta\pom.xml call mvn install:install-file -Dfile=jOOQ-lib\jooq-codegen-%VERSION%.jar -DgroupId=org.jooq -DartifactId=jooq-codegen -Dversion=%VERSION% -Dpackaging=jar %JAVADOC_JOOQ_CODEGEN% %SOURCES_JOOQ_CODEGEN% -DpomFile=jOOQ-pom\jooq-codegen\pom.xml call mvn install:install-file -Dfile=jOOQ-lib\jooq-codegen-maven-%VERSION%.jar -DgroupId=org.jooq -DartifactId=jooq-codegen-maven -Dversion=%VERSION% -Dpackaging=jar %JAVADOC_JOOQ_CODEGEN_MAVEN% %SOURCES_JOOQ_CODEGEN_META% -DpomFile=jOOQ-pom\jooq-codegen-maven\pom.xml call mvn install:install-file -Dfile=jOOQ-lib\jooq-scala-%VERSION%.jar -DgroupId=org.jooq -DartifactId=jooq-scala -Dversion=%VERSION% -Dpackaging=jar %JAVADOC_JOOQ_SCALA% %SOURCES_JOOQ_SCALA% -DpomFile=jOOQ-pom\jooq-scala\pom.xml
Linux Shell
#!/bin/sh VERSION=3.4.4 if [ -f jOOQ-javadoc/jooq-$VERSION-javadoc.jar ]; then JAVADOC_JOOQ=-Djavadoc=jOOQ-javadoc/jooq-$VERSION-javadoc.jar JAVADOC_JOOQ_META=-Djavadoc=jOOQ-javadoc/jooq-meta-$VERSION-javadoc.jar JAVADOC_JOOQ_CODEGEN=-Djavadoc=jOOQ-javadoc/jooq-codegen-$VERSION-javadoc.jar JAVADOC_JOOQ_CODEGEN_MAVEN=-Djavadoc=jOOQ-javadoc/jooq-codegen-maven-$VERSION-javadoc.jar JAVADOC_JOOQ_SCALA=-Djavadoc=jOOQ-javadoc/jooq-scala-$VERSION-javadoc.jar fi if [ -f jOOQ-src/jooq-$VERSION-sources.jar ]; then SOURCES_JOOQ=-Dsources=jOOQ-src/jooq-$VERSION-sources.jar SOURCES_JOOQ_META=-Dsources=jOOQ-src/jooq-meta-$VERSION-sources.jar SOURCES_JOOQ_CODEGEN=-Dsources=jOOQ-src/jooq-codegen-$VERSION-sources.jar SOURCES_JOOQ_CODEGEN_MAVEN=-Dsources=jOOQ-src/jooq-codegen-maven-$VERSION-sources.jar SOURCES_JOOQ_SCALA=-Dsources=jOOQ-src/jooq-scala-$VERSION-sources.jar fi mvn install:install-file -Dfile=jOOQ-pom/pom.xml -DgroupId=org.jooq -DartifactId=jooq-parent -Dversion=$VERSION -Dpackaging=pom mvn install:install-file -Dfile=jOOQ-lib/jooq-$VERSION.jar -DgroupId=org.jooq -DartifactId=jooq -Dversion=$VERSION -Dpackaging=jar $JAVADOC_JOOQ $SOURCES_JOOQ -DpomFile=jOOQ-pom/jooq/pom.xml mvn install:install-file -Dfile=jOOQ-lib/jooq-meta-$VERSION.jar -DgroupId=org.jooq -DartifactId=jooq-meta -Dversion=$VERSION -Dpackaging=jar $JAVADOC_JOOQ_META $SOURCES_JOOQ_META -DpomFile=jOOQ-pom/jooq-meta/pom.xml mvn install:install-file -Dfile=jOOQ-lib/jooq-codegen-$VERSION.jar -DgroupId=org.jooq -DartifactId=jooq-codegen -Dversion=$VERSION -Dpackaging=jar $JAVADOC_JOOQ_CODEGEN $SOURCES_JOOQ_CODEGEN -DpomFile=jOOQ-pom/jooq-codegen/pom.xml mvn install:install-file -Dfile=jOOQ-lib/jooq-codegen-maven-$VERSION.jar -DgroupId=org.jooq -DartifactId=jooq-codegen-maven -Dversion=$VERSION -Dpackaging=jar $JAVADOC_JOOQ_CODEGEN_MAVEN $SOURCES_JOOQ_CODEGEN_META -DpomFile=jOOQ-pom/jooq-codegen-maven/pom.xml mvn install:install-file -Dfile=jOOQ-lib/jooq-scala-$VERSION.jar -DgroupId=org.jooq -DartifactId=jooq-scala -Dversion=$VERSION -Dpackaging=jar $JAVADOC_JOOQ_SCALA $SOURCES_JOOQ_SCALA -DpomFile=jOOQ-pom/jooq-scala/pom.xml
The above scripts essentially check if any of Javadoc, Sources, and/or binaries are available in the distribution, and then install:
- The parent pom.xml
- The various artefact binaries, sources, javadocs, and pom.xml files
Advantages of this approach
Dependencies can now be referenced like any other type of dependency, as the artefacts are registered in your local repository. Moreover, they’re also available to your module’s own dependencies, transitively – which is probably what you want when you’re using jOOQ. Here’s how you’d then specify the dependencies:
<dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>${jooq.version}</version> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>sqljdbc4</artifactId> <version>3.0</version> <scope>provided</scope> </dependency>
Disadvantages of this approach
There is a manual step involved in the installation of the dependencies. If you don’t have the above scripts readily available, it can be quite tedious to figure out exactly how to import all those dependencies step by step into your repository. Specifically if you’re running a demo or prototype, this may lead to unexpected compilation failure in the worst moments.
The way to go
In an actual project setup, obviously, neither of the above approaches will be sufficient, and you’ll probably import the libraries into your local Nexus or Bintray or whatever repository you’re using. Just beware of potential restrictions on distribution that commercial deliverables may have.
A small tutorial about how to install artefacts into Nexus can be found here.
Reference: | How to Integrate Commercial Third-Party Artefacts into Your Maven Build from our JCG partner Lukas Eder at the JAVA, SQL, AND JOOQ blog. |
Another way is to use a local maven repository in your source code and point to that repo from your pom.xml. See https://devcenter.heroku.com/articles/local-maven-dependencies for an example.
I used a script someone provided at GitHub [1] for this purpose. It does the same as Thai describes: install the given jar(s) as local repository in the source repository, so that you can check those in with your version control.
[1] https://github.com/nikita-volkov/install-to-project-repo