Wednesday, December 3, 2014

Maven: Installing a Local JAR

What do I do when I have a 3rd party JAR that doesn't support Maven?

Maven tries to promote the notion of a user local repository where JARs, or any project artifacts, can be stored and used for any number of builds. Many projects have dependencies such as XML parsers and standard utilities that are often replicated in typical builds. Referencing a JAR outside the repository breaks this paradigm.

Frequently, you will have 3rd party JARs that you need to put in your local repository for use in your builds, since they don't exist in any public repository like Maven Central. By placing the JAR in our local repository, we create a default POM file, and can use this as the reference point in our own application.

Maven provides a goal to make the plugin installation easier and less error prone.


JAWS!


I want to use the Java API for WordNet Searching (JAWS).  This is not a Maven project. So we're going to have to install this JAR file locally to use it properly.

 I could reference this in my POM like this:
 <dependency>  
      <groupId>jaws</groupId>  
      <artifactId>jaws</artifactId>  
      <version>${jaws.version}</version>  
      <scope>system</scope>  
      <systemPath>${basedir}/../dependencies/jaws/1.2/jaws-bin.jar</systemPath>  
 </dependency>  

But then Maven will give me a warning
 $ mvn clean package  
 [INFO] Scanning for projects...  
 [WARNING]  
 [WARNING] Some problems were encountered while building the effective model for edu.smu.tspell.wordnet:edu.smu.tspell.wordnet:jar:0.0.1-SNAPSHOT  
 [WARNING] 'dependencies.dependency.systemPath' for jaws:jaws:jar should not point at files within the project directory, ${basedir}/../dependencies/jaws/1.2/jaws-bin.jar will be unresolvable by dependent projects @ line 53, column 14  
 [WARNING]  
 [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.  
 [WARNING]  
 [WARNING] For this reason, future Maven versions might no longer support building such malformed projects.  
 [WARNING]  
and subsequent POMs that use this POM will also include warnings.


Local Installation


Fortunately, performing the local installation of this JAR is not difficult.

The downside it hat every developer on my team will have to do this. Bear in mind, if there are multiple JARs to be installed locally, we could always script this. As provisioning requirements go, this doesn't qualify as onerous.

The installation goal is:
 mvn install:install-file -Dfile=c:\jaws-bin.jar -DgroupId=jaws -DartifactId=jaws -Dversion=1.2 -Dpackaging=jar  

My operational output is
 $ mvn install:install-file -Dfile=c:\jaws-bin.jar -DgroupId=jaws -DartifactId=jaws -Dversion=1.2 -Dpackaging=jar  
 [INFO] Scanning for projects...  
 [INFO]  
 [INFO] ------------------------------------------------------------------------  
 [INFO] Building edu.smu.tspell.wordnet 0.0.1-SNAPSHOT  
 [INFO] ------------------------------------------------------------------------  
 [INFO]  
 [INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ edu.smu.tspell.wordnet ---  
 [INFO] Installing c:\jaws-bin.jar to C:\Users\Craig Trim\.m2\repository\jaws\jaws\1.2\jaws-1.2.jar  
 [INFO] ------------------------------------------------------------------------  
 [INFO] BUILD SUCCESS  
 [INFO] ------------------------------------------------------------------------  
 [INFO] Total time: 1.233 s  
 [INFO] Finished at: 2014-12-03T08:58:42-08:00  
 [INFO] Final Memory: 17M/981M  
 [INFO] ------------------------------------------------------------------------  

Notice the repository location that the JAR was installed to:
C:\Users\Craig Trim\.m2\repository\jaws\jaws\1.2\jaws-1.2.jar
If I pull up that repository location, I notice that POM has been generated for me:
jaws-1.2.pom



The Generated POM


The Install Plugin has created a generic POM.

In this case the POM contains the minimal set of elements required by Maven: groupId, artifactId, version and packaging:
 <?xml version="1.0" encoding="UTF-8"?>  
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"  
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>jaws</groupId>  
  <artifactId>jaws</artifactId>  
  <version>1.2</version>  
  <description>POM was created from install:install-file</description>  
 </project>  



POM Relationships


And from here, I pull out the groupId, artifactId and version into my own POM:
 <properties>  
      ...  
      <jaws.version>1.2</jaws.version>  
      ...  
 </properties>  
 <dependencies>  
      ...  
      <dependency>  
           <groupId>jaws</groupId>  
           <artifactId>jaws</artifactId>  
           <version>${jaws.version}</version>  
      </dependency>  
      ...  
 </dependencies>  


Running the Full Install


Now I'm going to run the full install goal
mvn clean install
And in my operational output there are no warnings:
 $ mvn clean install  
 [INFO] Scanning for projects...  
 [INFO]  
 [INFO] ------------------------------------------------------------------------  
 [INFO] Building edu.smu.tspell.wordnet 0.0.1-SNAPSHOT  
 [INFO] ------------------------------------------------------------------------  
 [INFO]  
 [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ edu.smu.tspell.wordnet ---  
 [INFO] Deleting \projects\edu.smu.tspell.wordnet\target  
 [INFO]  
 [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ edu.smu.tspell.wordnet ---  
 [INFO] Using 'UTF-8' encoding to copy filtered resources.  
 [INFO] skip non existing resourceDirectory \projects\edu.smu.tspell.wordnet\src\main\resources  
 [INFO]  
 [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ edu.smu.tspell.wordnet ---  
 [INFO] Changes detected - recompiling the module!  
 [INFO] Compiling 10 source files to \projects\edu.smu.tspell.wordnet\target\classes  
 [INFO]  
 [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ edu.smu.tspell.wordnet ---  
 [INFO] Using 'UTF-8' encoding to copy filtered resources.  
 [INFO] skip non existing resourceDirectory \projects\edu.smu.tspell.wordnet\src\test\resources  
 [INFO]  
 [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ edu.smu.tspell.wordnet ---  
 [INFO] No sources to compile  
 [INFO]  
 [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ edu.smu.tspell.wordnet ---  
 [INFO] No tests to run.  
 [INFO]  
 [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ edu.smu.tspell.wordnet ---  
 [INFO] Building jar: \projects\edu.smu.tspell.wordnet\target\edu.smu.tspell.wordnet-0.0.1-SNAPSHOT.jar  
 [INFO]  
 [INFO] --- maven-install-plugin:2.4:install (default-install) @ edu.smu.tspell.wordnet ---  
 [INFO] Installing \projects\edu.smu.tspell.wordnet\target\edu.smu.tspell.wordnet-0.0.1-SNAPSHOT.jar to C:\Users\Craig Trim\.m2\repository\edu\smu\tspell\wordnet\edu.smu.tspell.wordnet\0.0.1-SNAPSHOT\edu.smu.tspell.wordnet-0.0.1-SNAPSHOT.jar  
 [INFO] Installing \projects\edu.smu.tspell.wordnet\pom.xml to C:\Users\Craig Trim\.m2\repository\edu\smu\tspell\wordnet\edu.smu.tspell.wordnet\0.0.1-SNAPSHOT\edu.smu.tspell.wordnet-0.0.1-SNAPSHOT.pom  
 [INFO] ------------------------------------------------------------------------  
 [INFO] BUILD SUCCESS  
 [INFO] ------------------------------------------------------------------------  
 [INFO] Total time: 2.511 s  
 [INFO] Finished at: 2014-12-03T09:01:21-08:00  
 [INFO] Final Memory: 25M/981M  
 [INFO] ------------------------------------------------------------------------  



With Jenkins


I've been struggling with this, and apparently I'm not the only one:

  1. [Stackoverflow] Jenkins can't find local Maven dependencies
    1. looks like this was a permissions issue
  1. [Stackoverflow] Managing third party JAR dependencies with Eclipse, Maven and Jenkins
    1. Recommends either Nexus from Sonatype
    2. Or using systemPath (highly discouraged)
  1. [Jenkins Bug Report] Unable to find manually installed Maven artifacts
    1. There does not appear to any official fixes (only workarounds)

I ended up using this approach:

 <dependency>  
      <groupId>jaws</groupId>  
      <artifactId>jaws</artifactId>  
      <version>1.2</version>  
      <type>jar</type>  
      <scope>system</scope>  
      <systemPath>/home/craig/jaws-bin.jar</systemPath>  
 </dependency>  

which is terrible.

Note that this is only for Jenkins-CI integration.  For local building, I don't need this.  But I couldn't find any other method for Jenkins to resolve the local JAR.



References

  1. Installing an artifact to a specific repository path

4 comments:

  1. very nicely expalined. struggling from 2 days with the same problem and now its resolved.
    awesum, you rock !!!!

    ReplyDelete
  2. Hey , It is really helped me a lot ... Thanks a ton for you ... Could you please me to write the script to add all the JARS(say if I have 100 JARS to be added) .. Please help me out on this

    ReplyDelete
  3. Hi, good explination, thx.
    i have a question please about jenkins. Jenkins can compile successfully java project which its dependencies exist inside pom.xml. But when project depend some jars in Tomcat_HOME/lib, jenkins fail to compile project.
    Did some one have an idea please about that?
    Thanks :)

    ReplyDelete
  4. You could use pom.basedir instead of basedir. For me the warning was removed..

    ReplyDelete