Maven: Including jar not found in public repository - maven-2

If I was to use a 3rd party library that was not in the maven public repository, what is the best way to include it as dependency for my project so that when someone else checks out my code it will still be able to build?
i.e.
My Application "A" depends on jar "B" which does not exist in the public repository. I, however, wish to add "B" as a dependency to "A" such that when a person on the other side of the world could check out the code and still be able to build "A"

You can install the project yourself.
Or you can use the system scope like the following:
<dependency>
<groupId>org.group.project</groupId>
<artifactId>Project</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/project-1.0.0.jar</systemPath>
</dependency>
systemPath requires the absolute path of the project. To make it easier, if the jar file is within the repository/project, you can use ${basedir} property, which is bound to the root of the project.

If you have a parent project with a module that is in this situation (requires a dependency not in a repository) you can setup your parent project to use the exec-maven-plugin plugin to auto-install your dependent file. For example, I had to do this with the authorize.net jar file since it is not publicly available.
Parent POM:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<inherited>false</inherited>
<executions>
<execution>
<id>install-anet</id>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>mvn</executable>
<arguments>
<argument>install:install-file</argument>
<argument>-Dfile=service/lib/anet-java-sdk-1.4.6.jar</argument>
<argument>-DgroupId=net.authorize</argument>
<argument>-DartifactId=anet-java-sdk</argument>
<argument>-Dversion=1.4.6</argument>
<argument>-Dpackaging=jar</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
In the above example, the location of the jar is in the lib folder of the "service" module.
By the time the service module enters the validate phase, the jar will be available in the local repository. Simply reference it in the way you set up the groupid, artifact, etc in the parent pom. For example:
<dependency>
<groupId>net.authorize</groupId>
<artifactId>anet-java-sdk</artifactId>
<version>1.4.6</version>
</dependency>

Using system scope may work but it is not recommended even in the Maven specification.
it is not portable.
from Maven book:
system- The system scope is similar to provided except that you
have to provide an
explicit path to the JAR on the local file system. This is intended to allow compilation
against native objects that may be part of the system libraries. The artifact is assumed
to always be available and is not looked up in a repository. If you declare the scope to
be system, you must also provide the systemPath element. Note that this scope is not
recommended (you should always try to reference dependencies in a public or custom Maven
repository).
The best approach is to install to your local repository or to your enterprise repository to be accessible to all your peers.
this is very easy if you are using a repository manager such as Nexus.

This solution worked for me;
1. Created a local-maven-repo in my project's root directory and copied all my jars in the
2. Executed the following command to generate the necessary pom files and metadata etc for each and every jar that I needed to use;
mvn deploy:deploy-file -DgroupId=<somegroupid> -DartifactId=<someartifact> -Dversion=1.0.0 -Durl=file:./local-maven-repo/ -DrepositoryId=local-maven-repo -DupdateReleaseInfo=true -Dfile=<path to jar file>
This generated a new jar file with a pom file inside the local-maven-repo and I was able to include into my project as a dependency like this;
<dependency>
<groupId>somegroupid</groupId>
<artifactId>someartifact</artifactId>
<version>1.0.0</version>
</dependency>
Then mvn package ensured that my project dependencies are resolved and packaged with my war file.

If you are using groovy/grail tool suite (GGTS) then you can directly import that third party dependency (but be sure you have that third party dependency in your local repository) using below steps :
Go to the Project Explorer and right click on project.
Click on import option.
Expend the maven option and select Install or deploy an
artifact to a maven repository and click next.
Brows and select that third party dependency using Artifact File
option and enter the detail of Group Id, Artifact Id and Version
using POM.xml file and click on finish
Wait some moment and possibly error would have gone for that problem.

Generally speaking, you should first put the 3rd party jar into your local repository. After that you can use it by adding the dependency into pom.xml.
For example.
1.put the jar into your local repository first:
mvn install:install-file -Dfile=<path-to-file>
Note: this command requires maven-install-plugin version 2.5 or later. If not, You can refer to Here
2.use the jar by adding the dependency into you project's pom.xml.
just add this into the pom.xml of your project:
<dependency>
<groupId>${the groupId in the jar's pom.xml}</groupId>
<artifactId>${the artifactId in the jar's pom.xml}</artifactId>
<version>${the version in the jar's pom.xml}</version>
</dependency>
3.you can then package or deploy your project by running mvn package or mvn deploy
The 3rd party jar will also be included in the package.

Related

Maven update jar before packaging in WAR

I have a project where I am packaging a WAR using simple maven-war-plugin. Along with all other dependencies one of the dependency say 'abc.jar' which is getting packaged in war contains a default spring configurations which I would like to update with the custom one before packaging. I have maven profile configured to be activated if following build command applied;
mvn clean install -DframeworkPacakging=XYZ
I am trying to use 'truezip-maven-plugin' to overwrite my custom spring configurations inside in 'abc.jar' present in 'target/aretfacts-id/WEB-INF/lib' but when maven-war-plugin finishes I loose my changes because war plugin takes the file from dependency definition. How can I solve this issue and what are my options?
P.S. Distributing configuration is not desirable as this setup would be used for Embedded Jetty Server running within Eclipse
to prevent inclusion of the original jar file, I would use go for approach suggested on: https://www.mail-archive.com/users#maven.apache.org/msg38537.html
Use <scope>provided</scope> for this dependency to keep it out of the
lib directory.
to include the repackaged one, I'd follow suggestion from: How to make Maven copy resource file into WEB-INF/lib directory?
Try changing the configuration of the maven war plugin to include a webResource:
<configuration>
<webResources>
<resource>
<directory>pathtorepackagedjar</directory>
<includes>
<include>**/abc.jar</include>
<includes>
<targetPath>WEB-INF/lib</targetPath>
</resource>
</webResources>
</configuration>

How to bundle JNLP API with Maven Project

I have a project where I need the JNLP API. I did not find an artifact for that on Maven Central, so I added an external Repository which offers that to my pom. That repository went offline this weekend. This is the second time something like this happened to me.
I know this is pretty much what Maven is not about, but really I just want that tiny jnlp-api-1.5.0.jar file to be
In my SCM (I don't want to roll my own Maven repository for just one dependency).
In the compile scope when the project builds.
Which knobs do I have to turn to accomplish this?
As of JDK 7.0, the JNLP API is being provided by the javaws.jar file in your JRE's lib directory, i.e., ${java.home}/lib/javaws.jar. It is possible to use the maven dependency scope system.
<project>
...
<dependencies>
<dependency>
<groupId>javax.jnlp</groupId>
<artifactId>jnlp-api</artifactId>
<version>7.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/javaws.jar</systemPath>
</dependency>
</dependencies>
...
</project>
You can put the JAR in your local repository using the install-file goal of the maven-install-plugin and reference it as you normally would in your POM. The command would be:
mvn install:install-file -Dfile=/path/to/jnlp-api-1.5.0.jar -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=1.5.0 -Dpackaging=<packaging>
Place this command in a script and check it into your SCM. That way, you (and anyone else working on this project) can install it easily to the local repo.

How to use classes of a maven project (packaging -> maven-plugin) in another maven project (packaging -> jar)

I have created a maven plugin. I have some classes in the plugin, which I want to make available to the plugin client after execution.
The problem is that a project of type maven-plugin is also a jar, so I simply can't use maven-jar-plugin and maven-install-plugin to install the jar (having the classes) as a dependency.
Any ideas on how to do this?
I have created a maven plugin. I have some classes in the plugin, which I want to make available to the plugin client after execution.
I see two options:
declare a dependency on the plugin in the client:
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<type>maven-plugin</type>
</dependency>
put the shared classes in a shared module (with a packaging of type jar) and declare a dependency on this shared module in both the client and the plugin.
Personally, I find the second option cleaner (and you won't get all the transitive dependencies of the plugin on the classpath).

Trigger a maven install command from another maven install command

Is there a way to trigger a maven install command from another maven install command?
In other words, I would like to be able to execute a maven install command on a maven project (in eclipse) and I want that this will automatically cause an install command on another maven project.
Is that possible?
The Maven way to "trigger" another build is to define a multi-module build. A parent pom project can specify modules, that will all be built using the standard lifecycle. So running mvn install on the parent would mean that each module is built in turn.
The parent is defined with pom packagin, and would have a modules declaration like this:
<modules>
<module>module-a</module>
<module>module-b</module>
</modules>
Alternatively it is possible to attach additional artifacts to a build so they are deployed alongside the primary artifacts (assuming they've already been packaged, you can use the build-helper-maven-plugin to attach an arbitrary file to your pom, so it will be deployed with the specified classifier. The following configuration will attach the specified file as my-artifact-1.0-extra.jar
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>/path/to/extra/file.jar</file>
<type>jar</type><!--or specify your required extension-->
<classifier>extra</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
As pointed out, the maven way to launch a goal (lets say mvn install) on a set of modules is to organize them as a multi-module project and to launch the goal on the parent pom. Behind the scene, Maven will use a "Maven reactor" for this work. The reactor will calculate the build order by doing a topological sort of the nodes of the directed graph constructed by the dependency relation between modules. This graph is constructed by looking at <modules> and <dependencies> tags in poms.
But launching maven from a parent is not the only option and maven offers more possibilities to play with the reactor (e.g. making a project and its dependencies or those that depend on it):
With maven 2.0.x you have to use the reactor plugin : http://maven.apache.org/plugins/maven-reactor-plugin/ (see Reactor: My New Favourite Maven Plugin too)
With maven 2.1+ you can use native command line options : http://www.sonatype.com/people/2009/03/maven-210-released/ (see the new build mode options -amd, -rf, -am, -pl)
Check it out, it might help you to achieve your goal.

How can maven be used in a continuous integration situation to install versioned artifacts in the repository?

We are in the process of converting our main build process from ant to maven. We use TeamCity for our Continuous Integration server (CI).
We'd like to use the CI server to kick off (nightly) builds whose version contain a build number, as in 1.0.0.build#. These builds would be installed in our local maven repository to be used by other projects. So the CI server would manage the versions, maven would build the project, and the maven repository would make the builds accessible to other projects.
I intended to initiate the build from the CI server using the following command:
mvn -Dversion=1.0.0.25 install
The project's pom would have a bogus version number, and the -D flag would override it, as in:
<version>0.0.0.0</version>
The problem with this method is that the maven install plugin only uses the version in the pom file, not the version passed in on the command line. This is noted in this maven issue.
So since this issue has existed since 08/2006 and has not been fixed, I assume that this is somehow not 'the maven way'. So my question is, how can maven be used in a continuous integration situation to install versioned artifacts in the repository?
Sounds like you want to build SNAPSHOT versions with unique versions.
So, in your POM declare the version as:
<version>#.#.#-SNAPSHOT</version>
Then, in the distributionManagement section of your POM, enable unique versions for the snapshotRepository via (see Maven's POM reference on this):
<snapshotRepository>
<uniqueVersion>true</uniqueVersion>
<id>your-snapshot-repo-id</id>
<name>Your Snapshots</name>
<url>http://your-snapshot-repo-url/maven</url>
</snapshotRepository>
FYI, note that Maven conventions recommend versions be declared as major.minor.revision. So, 1.0.25 instead of 1.0.0.25. If you're able to use this versioning scheme, things will work more smoothly in a Maven world.
Matthew's answer provides a solution where the artifacts get uploaded into the local and remote repository having the desired version number, i.e. the paths inside the repository are contain the correct version numbers, however, Maven installs and deploys always the source POM file that would still contain the ${ciVersion} in the version element.
If you have a multi-module with a common parent like this:
<project xmlns="..." xmlns:xsi="..." xsi:schemaLocation="...">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>myParent</artifactId>
<groupId>com.stackoverflow</groupId>
<version>${ciVersion}</version>
</parent>
<artifactId>myChild</artifactId>
...
</project>
you won't be able to reference a dedicated version of the myChild module, as the dependency resolution will exist with an error that it cannot find the myParent module with version ${ciVersion}.
However, you could use the resolve-pom-maven-plugin that uploads a POM into the local and remote repository where all variables inside the POM get substituted by their actual values. In order to do this, you have to add the following snippet into your (parent) POM:
...
<build>
<plugins>
<plugin>
<groupId>com.sap.prd.mobile.ios.maven.plugins</groupId>
<artifactId>resolve-pom-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>resolve-pom-props</id>
<goals>
<goal>resolve-pom-props</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
Shek's answer is probably 'the maven way', so I'll accept it as the correct answer. However, we are not ready to change our conventions, so here is the workaround that we are using.
By using a level of indirection you can pass a version number in to the pom at build time and have the install and deploy plugins use them. For example:
<project xmlns="..." xmlns:xsi="..." xsi:schemaLocation="...">
<modelVersion>4.0.0</modelVersion>
<groupId>com.stackoverflow</groupId>
<artifactId>stackoverflow</artifactId>
<version>${ciVersion}</version>
<packaging>jar</packaging>
<name>StackOverflow</name>
<properties>
<ciVersion>0.0.0.0</ciVersion>
</properties>
...
</project>
We cannot override ${project.version} directly. So instead, we add a second property called 'ciVersion' and give it a default value of '0.0.0.0' in the properties section. Now the CI server can specify a version number by overriding the ciVersion property on the command line. As in:
mvn -DciVersion=1.0.0.25 install
The install and deploy plugins will use the value of the ciVersion property that was passed in whenever ${project.version} is referenced, as expected, and the default value will be used when no version is provided on the command line. This allows us to switch to maven with minimal impact on our process. In addition, this workaround is unobtrusive, allowing for an easy switch to the SNAPSHOT functionality when desired.