MulitModule project dependency management - maven

I am working on the project with the project structure as
root
lib
xyz.jar
modules
module1
module2
Now I want to include the xyz.jar in the module1 but owing to the multimodule structure of the project, I am not able to add the jar directly through maven.
I tried using
<plugin>
<groupId>org.commonjava.maven.plugins</groupId>
<artifactId>directory-maven-plugin</artifactId>
<version>0.1</version>
<executions>
<execution>
<id>directories</id>
<goals>
<goal>highest-basedir</goal>
</goals>
<phase>initialize</phase>
<configuration>
<property>multi.module.project.root.dir</property>
</configuration>
</execution>
</executions>
</plugin>
and then using
<dependency>
<groupId>org.abc.com</groupId>
<artifactId>xyz</artifactId>
<version>0.1.0</version>
<scope>system</scope>
<systemPath>${multi.module.project.root.dir}/lib/xyz.jar</systemPath>
</dependency>
but throws error to specify absolute path of jar.
next I tried using the de
pendency management in parent pom by specifying
<dependency>
<groupId>org.abc.com</groupId>
<artifactId>xyz</artifactId>
<version>0.1.0</version>
<scope>system</scope>
<systemPath>${pom.basedir}/lib/xyz.jar</systemPath>
</dependency>
This resolves the dependency but I am not able to use the dependency in the child pom of module1
How can I solve this

The documentation of the directory-maven-plugin you are using explicitly says about the variables produced by the plugin:
They will be useful ONLY IN PLUGIN CONFIGURATIONS, NOT DURING POM INTERPOLATION.
This means you cannot use it like what you are doing.
As an alternative, I would consider referring to this SO answer.

Related

Remove test dependencies from deployed POM

I have a fairly typical pom.xml which builds a jar:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mygroup</groupId>
<artifactId>my-lib</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I thought it'd be nice to remove the test dependencies (junit-jupiter and its dependencies) from the copy of the POM which is deployed with the jar, just to avoid imposing them on users of the jar. After all, test code isn't included in the deployed jar, so it shouldn't matter to users of the jar how the tests are written.
I figured this would be a common use case for maven-shade-plugin. But this use case doesn't seem to be mentioned in its documentation. And I wasn't able to make the shade plugin remove the junit-jupiter dependency from the reduced POM.
Is there a straightforward way to remove dependencies from the deployed POM? Am I worrying about nothing?
I saw this question, but it seems to be about removing test dependency contents from the uber jar. In my case, I'm not actually creating an uber jar. I'm just trying to use the shade plugin for its ability to rewrite the POM.
If you want to remove unnecessary parts from the deployed POM, you can use the flatten maven plugin:
https://www.mojohaus.org/flatten-maven-plugin/flatten-mojo.html
One of the features is to remove the test dependencies.

Install a 3rd-party dependency with maven before dependencies are resolved

I would like to deploy a maven project that depends on a 3rd-party jar, located in a "lib/" directory that is distributed with my project source.
The usual way to do this (as explained in other answers) is to have the user install the jar into a local maven repository before building the project, by typing a command such as mvn install:install-file at the shell.
This manual solution won't do for deployment, however (because requiring users to manually install dependencies is so 1998...). So I thought I'd specify an install-file goal in my pom.xml:
<dependency>
<groupId>edu.my.id</groupId>
<artifactId>myartifact</artifactId>
<version>1.0</version>
</dependency>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<id>install-jar-lib</id>
<phase>validate</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>edu.my.id</groupId>
<artifactId>myartifact</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<file>${project.basedir}/lib/myartifact.jar</file>
<generatePom>true</generatePom>
</configuration>
</execution>
</executions>
The problem is that maven attempts to resolve dependencies before install-file runs, even when I specify it to run as early as the validate phase. It thus complains that it cannot find the dependency.
This question has been asked before, and a few unpleasantly complicated solutions have been offered such as these:
Run maven-install-plugin during the clean phase and require users to run mvn clean before building the artifact.
Set up multiple modules, as described here.
Use <systemPath> to load the jar as a system library. (This doesn't meet my requirements, because I am using maven-dependency-plugin to copy dependency jars into the deployed application directory, which ignores system libraries.)
Write a custom plugin.
None of these satisfy me. This seems like a routine task any build system encounters. There must be a simpler way to install dependencies with maven.
The solution that worked for me was to use both install-file and <systemPath>.
<dependency>
<groupId>edu.my.id</groupId>
<artifactId>myartifact</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/myartifact.jar</systemPath>
</dependency>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<id>install-jar-lib</id>
<phase>validate</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>edu.my.id</groupId>
<artifactId>myartifact</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<file>${project.basedir}/lib/myartifact.jar</file>
<generatePom>true</generatePom>
</configuration>
</execution>
</executions>
This way, when Maven compiles the project, it resolves the 3rd-party dependency as a system library. But it also installs the library into the local maven repository, so that maven-dependency-plugin's copy-dependencies goal is able to find it.

Maven shaded jar used as external project dependency

I have used maven shade plugin in my project to relocate all dependency jar classes under one package e.g., org.shade.*
When I try to use that shaded jar in other application as maven dependency it pulls dependency jar's.
My expectation is when uber/shaded jar included as maven dependency it should not pull any other dependent class jar, Since already those classes are repackaged within shaded jar.
The classic scenario is:
A project producing an uber-jar has its own dependencies (dependency elements in its pom.xml file) which then are packaged together in one uber-jar as Maven artifact
When using this uber-jar as a dependency (dependency element) of another project, Maven would then inspect its <artifact>-<version>.pom file (published together with the final artifact into the Maven repository), which is basically a renamed copy of its original pom.xml file, where dependencies (dependency element) were declared (exactly the dependencies packaged into the uber-jar).
Since you already have them packed, you would then like to ignore the .pom file (and its dependencies element), for that you need to add exclusions as following:
<dependency>
<groupId>com.sample</groupId>
<artifactId>something-uber</artifactId>
<version>some-version</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
Note: the feature above is only available since Maven 3.2.1.
As such, you are making clear to Maven you don't want any transitive dependency and Maven dependency mediation would then not trigger them.
As a side note: this is not a good practice to have an uber-jar as dependency of a project: it will just make maintenance harder since you can't control transitive dependencies via dependencyManagement or dependencies order of the dependent project. As such you will always need to re-pack the uber jar whenever a dependency (one of its transitive one) would need maintenance (change version and so on) and have much less control on the dependent project (again, harder maintenance).
As the pom.xml on your source project that produces the uber jar declares transitive dependencies, if you include it as dependency into an external project then Maven will try to get these ( even if these are already included on the uber jar ).
I share a solution that let you avoid to explicitly exclude all transitive dependencies including it into an external project as explained by #A_DiMatteo on his solution ( I agree also with him about to avoid to use uber jar as dependency if not strictly necessary to do it for some reason ). As result then you should be able to include your uber jar dependency without using exclusions element as follow:
<dependency>
<groupId>com.sample</groupId>
<artifactId>something-uber</artifactId>
<version>some-version</version>
</dependency>
Premise: my goal was to provide both uber ( without transitive dependency declared on pom ) and thin jars on my repository. So my solution "A" is based on this scenario and currently has the limit that the shaded jar is uploaded 2 times on repository.
To provide only the uber jar see "B" solution below
For a possible solution for "A" limit see the UPDATE section at the end
A) Provide both thin and uber jars on repository
1- On your source project configure on your something module pom.xml the following maven-shade-plugin as follow:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>something-uber-${project.version}</finalName>
</configuration>
</execution>
</executions>
</plugin>
Then use the build-helper-maven-plugin plugin to attach the new artifact with "uber" classifier on module:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>
${project.build.directory}/something-uber-${project.version}.jar
</file>
<classifier>uber</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
This will generate as results of the maven install phase the following two jars on target/ directory:
40K something-0.1.0.jar
7M something-uber-0.1.0.jar
WARN: Executing then the maven deploy phase both jars will be uploaded on repository! The target here should be to upload only the thin jar skipping deploy for shaded jar in order to leave it as a local artifact ( See the UPDATE section at the end for a possible fix )
2- Create then another module on your source project named something-uber adding following dependencies and plugin:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>something</artifactId>
<version>${project.version}</version>
<classifier>uber</classifier>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Note the followings on including the dependency:
the classifier should be equals to uber ( the one you've specified attaching new artifact using build-helper-maven-plugin on first module )
the exclusions are specified.
Executing at the end the maven deploy phase on this module the shaded jar will be uploaded on repository and you we'll be able to add it as dependency into an external project as follow:
<dependency>
<groupId>com.sample</groupId>
<artifactId>something-uber</artifactId>
<version>0.1.0</version>
</dependency>
B) Provide only uber jar on repository
Starting from solution "A" if you want to avoid to provide the thin jar on repository you should avoid on point 1 to specify finalName on maven-shade-plugin configuration and so avoid also the build-helper-maven-plugin plugin as there isn't a new artifact to attach.
Doing this, deploying the module you'll have only the uber jar on target/ as default one ( without classifier ):
7M something-0.1.0.jar
You should also skip the upload otherwise you'll have also here two fat jars uploaded ( something-0.1.0.jar & something-uber-0.1.0.jar ).
To do this add the following plugin on the same module:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
At the end on point 2 just avoid to specify the classifier on adding the dependency as follow:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>something</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
UPDATE: Skip first shaded jar upload on A) solution
After searching for a solution for a while without success I decided to fork the maven-deploy-plugin plugin from GitHub and work for a new feature in order to skip shaded jar created on first module adding the plugin configured as follow:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.0.0-SNAPSHOT</version>
<configuration>
<skipAttachedArtifacts>
<artifact>
<groupId>com.sample</groupId>
<artifactId>something</artifactId>
<version>${project.version}</version>
<packaging>jar</packaging>
<classifier>uber</classifier>
</artifact>
</skipAttachedArtifacts>
</configuration>
</plugin>
Currently using the maven-deploy-plugin plugin all artifacts are excluded from deploy while target here is to exclude only a specific one. On my fork I've introduced the "skipAttachedArtifacts" configuration parameter in order to specify attached artifacts to exclude from deploy.
Here is the link on my forked project on GitHub:
https://github.com/gregorycallea/maven-deploy-plugin
Here the link instead to the pull request I've submitted on apache plugin project:
https://github.com/apache/maven-deploy-plugin/pull/3

How to build and package two jar's with different versions having same groupId and artifactId under maven pom.xml

How to build and package two jar's with different versions having same groupId and artifactId under maven pom.xml.
Basically I need to package both the version jar file under my war file lib directory.
Assuming both versions have different packages and class names i.e no class naming conflict issue.
Eg:
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>5.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.0.0.Final</version>
</dependency>
yeah its Possible the thing needed is just add some rules in pom.xml as that looks similar to this:
<executions>
<execution>
<id>pack-dependencies</id>
<phase>package</phase>
<goals>
<goal>pack-dependencies</goal>
</goals>
<configuration>
<!-- configure the plugin here -->
</configuration>
</execution>
</executions>
I Hope this will help you at least up to the level

Can I have maven artifact run maven plugin when it is installed?

I have created a Maven plugin (called unpackTemplates) that unpacks a dependency jar file and copies resource files (in this case, templates) from it into a specific location in a project.
Right now, I put the following into the pom file of every project that has a dependency with templates. It looks like:
<project>
<groupId>DuriansAreDope</groupId>
<artifactId>DuriansAreDope</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugin>
<groupId>mycorp</groupId>
<artifactId>unpackTemplates</artifactId>
<version>1.0</version>
<executions>
<execution>
<configuration>
<groupId>com.mycorp.lib</groupId>
<version>1.0</version>
<artifactId>Lib-With-Templates</artifactId>
</configuration>
<goals>
<goal>unpackTemplates</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
<pluginManagement>....</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>com.mycorp.lib</groupId>
<artifactId>Lib-With-Templates</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
The above project pom works for us. It calls the plugin and the plugin does it's job. However, we'd like to avoid adding the plugin section to the pom of every project.
It would make more sense to put that plugin section in the dependencies pom. This way the project pom does not need to be modified beyond adding the <dependency> tags as usual. And the dependency has it's plugin run wherever it is installed.
I've seen that the pom file for Gson contains a <build><plugins>...</plugins></build> section in it. When I give my dependencies the following pom files, however, the plugin is not run (although the dependency is found, downloaded, installed, etc correctly).
<project>
<groupId>com.mycorp.lib</groupId>
<artifactId>Lib-With-Templates</artifactId>
<version>1.0</version>
<build>
<plugin>
<groupId>mycorp</groupId>
<artifactId>unpackTemplates</artifactId>
<version>1.0</version>
<executions>
<execution>
<configuration>
<groupId>com.mycorp.lib</groupId>
<version>1.0</version>
<artifactId>Lib-With-Templates</artifactId>
</configuration>
<goals>
<goal>unpackTemplates</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
<pluginManagement>....</pluginManagement>
</build>
</project>
Any ideas what I'm doing wrong, or if the Gson pom is simply doing something else entirely?
(NB: The groupId/version/artifactIds in <configuration> are necessary because they are (string) parameters to the plugin; presumably if I got the run-straight-from-dependency approach working I could refactor them away, but again, it's not even running the kludgy version with parameters.)
two points:
First I agree with khmarbaise in that you don't need a plugin of your own for those tasks. To unpack to a specific location you can use dependency:unpack-dependencies and outputDirectory parameter.
If you need more configuration you can use the assembly plugin to structure your artifact (which you want to unpack).
For the second point it seems to me that you want to use the contents of your lib-with-templates in many projects. Why don't you add the plugin and dependency to a parent pom which you include in every pom where you need it? Then you don't need to declare it in "every pom". If you don't really need it in every pom you can put it in a profile and choose a proper activation for it.
HTH!

Resources