Maven modules are trying to use parent dependencies - maven

I have a maven project where the parent module has a lib directory containing various jars that are necessary for compilation, but aren't included in the final product. When I try to get the children modules to build it fails. It says "The following artifacts could not be resolved" then eventually says "Could not find artifact local_dependency at C:\path\to\project\modules\module_name\lib\local_dependency.jar".
The children modules do not depend on the libraries that the parent uses, however it still wants to include them. Is there an option I need to set to prevent this?
Parent Pom snippet:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<currentVersion>1.0.0</currentVersion>
</properties>
<groupId>com.project</groupId>
<artifactId>project_artifact</artifactId>
<packaging>pom</packaging>
<version>${currentVersion}</version>
<modules>
<module>modules/module_name</module>
</modules>
<dependencies>
<dependency>
<groupId>group.id</groupId>
<artifactId>local_dependency</artifactId>
<version>1.0</version>
<systemPath>${basedir}/lib/local_dependency.jar</systemPath>
<scope>system</scope>
<optional>true</optional>
</dependency>
</dependencies>
Child pom snippet:
<parent>
<groupId>com.project</groupId>
<artifactId>project_artifact</artifactId>
<version>${currentVersion}</version>
<relativePath>../../</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>net.some.dependency</groupId>
<artifactId>artifact_name</artifactId>
<version>1.0.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.project</groupId> <!-- The child depends on the parent for the parent's API-->
<artifactId>project_artifact</artifactId>
<version>${currentVersion}</version>
<type>jar</type>
</depdencency>
</dependencies>
So from this, the child pom will attempt to include group.id:local_dependency from project_base/modules/module_name/lib/local_dependency.jar but it doesn't exist and doesn't need to exist.

You can exclude specific transitive dependencies in the dependency declaration. In your case, the following change in the child pom's dependency on the parent should get the build working:
<dependency>
<groupId>com.project</groupId> <!-- The child depends on the parent for the parent's API-->
<artifactId>project_artifact</artifactId>
<version>${currentVersion}</version>
<type>jar</type>
<exclusions>
<exclusion>
<groupId>group.id</groupId>
<artifactId>local_dependency</artifactId>
</exclusion>
</exclusions>
</dependency>

The child inherits the parent's dependencies, whether or not you include the dependency explicitly. Two possible ways to resolve the issue are:
Don't build any jar artifact in the parent - create a sub-module for this and use the sub-module as a dependency in its siblings.
Use a fixed path (not relative to ${basedir}, since this changes in each module build, which tries to resolve the location anew). If you always build from the parent's directory, you could use ${user.dir}.

Related

How should dependencies between modules be declared in a maven multi-module project?

Assume I have a maven multi-module project consisting of parent P and its modules A and B. How should a dependency of B to A be declared?
Until today I always used the following in B:
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
</dependency>
But a colleague just mentioned that it is also possible to create a dependency management entry for A in parent P
<depednencyManagement>
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
</dependency>
</dependencyManagement>
and then B only needs to specify:
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
</dependency>
</dependencies>
Is there any downside to either of those methods? Does maven intend one to be actually used? Or is there actually another style I'm missing?
In the project I'm working all modules have the same version and we are having much more than 3 modules and also some deeper nesting than only 2 levels. Does this have an influence on which declaration style should be preferred?

Avoid wrong version interpolation if child's pom version is different from those of the parent's aggregator pom and its sub modules

Problem description
We have a Maven aggregator pom with some child poms (modules) all having the same version:
pom.xml (parent zoo, version 2.0.0)
|-- pom.xml (child module cat, version 2.0.0)
|-- pom.xml (child module dog, version 2.0.0)
|-- ...
Within the dependency management section all children are declared with the project version to ease declaration of dependencies.
The parent pom looks like
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0</version>
<packaging>pom</packaging>
<modules>
<module>cat</module>
<module>dog</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<version>${project.version}</version>
</dependency>
<!-- other child modules go here -->
</dependencies>
</dependencyManagement>
The child poms are defined as
<parent>
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0</version>
</parent>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dog</artifactId>
</dependency>
</dependencies>
There is another pom which declares the parent pom as its parent too (inheritance) but is not listed as sub module in this parent (no aggregation). This pom has a different version.
<parent>
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0</version>
</parent>
<groupId>com.acme</groupId>
<artifactId>boo</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dog</artifactId>
</dependency>
</dependencies>
Actually we have expected that the version of the dependency com.acme.dog is pulled from the dependency management section of the parent pom com.acme.zoo and is equal to 2.0.0. However the Maven documentation on project interpolation and variables says
One factor to note is that these variables are processed after inheritance as outlined above. This means that if a parent project uses a variable, then its definition in the child, not the parent, will be the one eventually used.
That is: in the reactor build the variable ${project.version} used in the dependency management section of the parent pom com.acme.zoo is evaluated with respect to com.acme.bar and equal to 1.0.0 what is not as intended.
Note
There is a workaround with using a variable in the parent pom which has to be kept in sync with the parent pom versions. However, this solution is incompatible with the Maven Release Plugin.
Question
How can we achieve the desired behaviour
aggregator pom with children having the same version
declaration of children in the dependency management section to ensure that all dependencies have the same version
use of inheritance together with different versions
compatibility with maven-release-plugin
without the pitfalls of project interpolation of variables?
The maven release plugin is able to change the versions of the dependencies managed in the parent pom.
So if you define your maven parent like this:
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>cat</module>
<module>dog</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<!-- other child modules go here -->
</dependencies>
</dependencyManagement>
As you see the versions of the parent and the managed dependency are the same. I set them to a SNAPSHOT version because the release plugin will create the final versions on release:perform
Your child poms can stay as you had them.
Because in your setup, your parent project is also the reactor you can then call
mvn release:perform -DautoVersionSubmodules=true
which will update the version of the parent in all submodules when you run this command. That option is essentially the same as if you run
mvn versions:update-child-modules
meaning it will change the child poms.
After you run the mvn release:perform command your parent pom will look like this:
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>cat</module>
<module>dog</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>
<!-- other child modules go here -->
</dependencies>
</dependencyManagement>
and your child poms like this
<parent>
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.1-SNAPSHOT</version>
</parent>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dog</artifactId>
</dependency>
</dependencies>
The final versions will only exist in the tag created by the release:prepare command.
PS: You may define other versions for the final and the next development version when they are prompted after running the release:prepare command.
The simplest solution is modify pom of zoo and replace <version>${project.version}</version> with <version>2.0.0</version>
Please note:
when you change version to next number, for example 2.0.1, with
versions-maven-plugin, dependency management section will be also
updated.
Spring use simplest solution, see
http://central.maven.org/maven2/org/springframework/spring-framework-bom/4.2.7.RELEASE/spring-framework-bom-4.2.7.RELEASE.pom
Summary: using <version>${project.version}</version> in dependency management is wrong idea.
From Maven Introduction to the pom : http://maven.apache.org/guides/introduction/introduction-to-the-pom.html
Project Inheritance > Example 1 > The Solution
Alternatively, if we want the groupId and / or the version of your
modules to be the same as their parents, you can remove the groupId
and / or the version identity of your module in its POM.
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
My approach to that is to track it in the child POM. It's a bit less typing overall, close to where the actual dependency lives and is low maintenance for most projects. YMMV
<dependencies>
...
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>foo-sibling</artifactId>
<version>${project.version}</version>
</dependency>
...
</dependencies>

Maven issue when overriding an environment specific systemPath property

I experienced issues with a maven build that does not behave the same way if done on Windows (like they were done in the past) or Linux (like I want to do them now).
I want to build a project that has a dependency on another project that pom that itself imports a pom that contains a Windows path.
my project | other project
|
mybuild -------|------> pom --------> pom with systemPath
dependency import
|
But in a nutshell, here is my pom:
<groupId>test.properties</groupId>
<artifactId>buildme</artifactId>
<version>1.0-SNAPSHOT</version>
...
<dependencies>
<dependency>
<groupId>test.properties.installme</groupId>
<artifactId>module</artifactId>
<version>1.0-SNAPSHOT</version>
<type>pom</type>
</dependency>
</dependencies>
And I depend on a pom that looks like this (not under my control)
<groupId>test.properties.installme</groupId>
<artifactId>module</artifactId>
<version>1.0-SNAPSHOT</version>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test.properties.installme</groupId>
<artifactId>dependency</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
and the problem lies in this last pom (not under my control):
<modelVersion>4.0.0</modelVersion>
<groupId>test.properties.installme</groupId>
<artifactId>dependency</artifactId>
<version>1.0-SNAPSHOT</version>
...
<properties>
<com.sun.tools.path>D:/java/jdk1.8.0_65/lib/tools.jar</com.sun.tools.path>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${com.sun.tools.path}</systemPath>
</dependency>
</dependencies>
</dependencyManagement>
I have no control on the other project in question. I totally agree that a refactoring to use environment variable in place of the hard coded paths would solve my problem.
But instead the Windows path is defined in a property. One would think that overriding the value of the property depending on my platform would be enough. But it is not.
Unfortunately in this precise case case maven seems to behave to behave poorly.
Before applying any property override in any form (in settings.xml, -Dproperty=, redefinition in root pom), maven starts building the effective pom. And during that step, if it finds the pattern I mentioned above (a dependency on another pom that itself imports a pom that contains a Windows path), then it says:
The POM for <groupId>:<artifactId>:jar:<version> is invalid, transitive dependencies (if any) will not be available
As a consequence, my project needs to explicitly define all the dependencies of the second project. And I cannot rely on transitive dependencies which gives me a lot of trouble.
In order to illustrate the issue, I created a minimal example showing the problem. It can be found here:
https://github.com/fabricepipart/test-properties
Do you see any workaround for this?
Any way to override the value of the property and still benefit from the maven transitive dependencies?
Thanks a lot

Multi-module maven build : different result from parent and from module

I am migrating an application from ant build to maven 3 build.
This app is composed by :
A parent project specifying all the modules to build
A project generating classes with jaxb and building a jar with them
A project building an ejb project
3 projects building war modules
1 project building an ear
Here is an extract from my parent pom :
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<packaging>pom</packaging>
<version>04.01.00</version>
<modules>
<module>../PValidationJaxb</module> <-- jar
<module>../PValidation</module> <-- ejb
<module>../PImport</module> <-- war
<module>../PTerminal</module> <-- war
<module>../PWebService</module> <-- war
<module>../PEAR</module> <-- ear
</modules>
I have several problems which I think have the same origin, probably a dependency management issue that I cannot figure out :
The generated modules are different depending on if I build from the parent pom or a single module. Typically if I build PImport only, the generated war is similar to what I had with my ant build and if I build from the parent pom, my war took 20MB, a lot of dependencies from other modules had been added. Both wars are running well.
My project PWebService has unit tests to be executed during the build. It is using mock-ejb which has cglib as dependency. Having a problem of ClassNotFound with this one, I had to exclude it and add a dependency to cglib-nodep (see last pom extract). If I then build only this module, it is working well. But if I build from the parent project, it fails because other dependencies in other modules also had an implicit dependency on cglib. I had to exclude it in every modules pom and add the dependency to cglib-nodep everywhere to make it run.
Do I miss something important in my configuration ?
The PValidation pom extract :
It is creating a jar containing an ejb with interfaces generated by xdoclet, as well as a client jar.
<parent>
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<version>04.01.00</version>
</parent>
<artifactId>P-validation</artifactId>
<packaging>ejb</packaging>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>P-jaxb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.5.ga</version>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
</dependency>
...
[other libs]
...
</dependencies>
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<ejbVersion>2.0</ejbVersion>
<generateClient>true</generateClient>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xdoclet-maven-plugin</artifactId>
...
The PImport pom extract :
It depends on both Jaxb generated jar and the ejb client jar.
<parent>
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<version>04.01.00</version>
</parent>
<artifactId>P-import</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>P-jaxb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>P-validation</artifactId>
<version>${project.version}</version>
<type>ejb-client</type>
</dependency>
...
[other libs]
...
</dependencies>
The PWebService pom extract :
<parent>
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<version>04.01.00</version>
</parent>
<artifactId>P-webservice</artifactId>
<packaging>war</packaging>
<properties>
<jersey.version>1.14</jersey.version>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.rte.etso</groupId>
<artifactId>etso-validation</artifactId>
<version>${project.version}</version>
<type>ejb-client</type>
</dependency>
...
[other libs]
...
<dependency>
<groupId>org.mockejb</groupId>
<artifactId>mockejb</artifactId>
<version>0.6-beta2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib-full</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Many thanks
Solution after modification of the configuration :
When I got the projects already mavenized, it didnt respect the folder layout convention, but as it was declared in the pom where to find the sources, I thought it would be working.
Anyway, i changed it to match the recommended structure.
To build a single module I was executing mvn clean install directly at its level. It is this way I obtained a different result (which is in fact the one I wanted).
Anyway, my problem is solved, I put all the dependencies of the PValidation project as provided, as I am only including the generated client in other modules and they dont require all what is needed for the implementation.
But still I dont get why I had different result for the same configuration.
The first important thing is you should create the structure of your project appropriate to the modules structure which means having the following folder structure:
+-- parent
+-- PValidationJaxb
+-- PValidation
+-- PImport
+-- PTerminal
+-- PWebService
+-- PEAR
This means having a pom.xml which contains the modules definition in the parent folder.
if you follow the above recommendation you can simplify the modules list to the following:
<modules>
<module>PValidationJaxb</module> <-- jar
<module>PValidation</module> <-- ejb
<module>PImport</module> <-- war
<module>PTerminal</module> <-- war
<module>PWebService</module> <-- war
<module>PEAR</module> <-- ear
</modules>
Furthermore a best practice in Maven is to use lowercase artifacts which mean in your case pvalidationjaxb instead of PValidationJaxb.
An other important thing is your version which does NOT follow the Maven conventions. Furthermore your version will be from the Maven point of view a release which is not the case you are doing development on this. In Maven you should use a so called SNAPSHOT for such purposes like 1.0.0-SNAPSHOT.
I hope you have followed the folder layout recommendation of Maven which says to put production code (which will be packaged into the resulting jar) into src/main/java whereas test code into src/test/java.
The problem you described having different dependencies sounds weired. The question is how have you tried to build a single moduel? This can usualy be achieved by using the following from the parent location:
mvn -pl module clean package
The problem with your unit tests sounds like a missing dependencies etc. but here is the questions how have you tried to run the unit tests and have you configured maven-surefire-plugin ? Or do you have integration tests? This is only a guess cause i don't see any configuration of Maven plugins in your poms.

Dependeny Management using POM import

I am creating a project 'test-jar' in my local and i am using pom file which I don't have write access as Parent of 'test-jar' project. The parent project has already defined depedencyManagement with old versions.
As I have to update dependency versions in my project and planning to override parent's dependency Management. So, I have created another POM file with my own dependency Management and imported into 'test-jar' project.
My Project :
<project>
<artifactid>test-jar</artifactid>
<parent>
<artifactId> test-parent </artifactId>
</parent>
<dependencies>
<dependency>
<artifactId>jar/artifactId>
</dependency>
<dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>custom-pom</artifactId>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
</project>
My Parent Project:
<project>
<artifactid>test-parent</artifactid>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>jar/artifactId>
<version>1.0</version>
</dependency>
</dependencyManagement>
</project>
My Custom POM for updated dependencyManagement:
<project>
<artifactid>custom-pom</artifactid>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>jar</artifactId>
<version>3.0</version>
</dependency>
</dependencyManagement>
</project>
The problem is, I am always getting dependency version from parent pom, though i have imported new dependency management in project.
I am using Maven 2.2.1 version here.
Is there any solution how to overwrite Dependency Management from Parent POM ?
Based on the documentation:
This scope is only used on a dependency of type pom in the
section. It indicates that the specified POM
should be replaced with the dependencies in that POM's
section. Since they are replaced, dependencies
with a scope of import do not actually participate in limiting the
transitivity of a dependency.
Apart from your problem you can simply use differerent version which are different of the onses defined in the parent pom's dependencyManagement. Furthermore you could create a separate pom wich defines the dependencies with new version (dependencyManagement) and inherits from the given parent.

Resources