Maven Inheritance and Distribution Management - maven

I have developers who use Maven parents external to my organisation. For this particular case the parent is the spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
Their builds are working and they have been testing against these dependencies for a long time, I ideally do not want to change their inheritance.
The problem I have as a Release Engineer is that the artifacts produced need to be stored in an internal Maven Repository. We've historically done that by having a Maven Parent that defines the and nothing else, that all projects had as the root of their inheritance chain.
I could end up managing hundreds of POMS and I don't want to put in each one as if we have to move the internal Maven repository I will have to manage a ridiculous number of projects to reflect the change.
Is there any way I can set where I essentially don't have write access to parents? Can this be set in MAVEN_OPTS or as a properties file on the CI servers? I have tried using properties-maven-plugin to input all of our properties but distributionManagement won't accept a property as a variable.

Keeping your org parent pom (other than the parent element you specified earlier) would need you to bring Spring Boot dependencies as a bom:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.4.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
But I think the less intrusive way might be to set the proper version to your modules using:
mvn versions:set before building the artifacts and deploying to Nexus (or other Maven repo manager)

Related

Retrieving the top-level version from sub modules in Maven

This is a version of the question posted in Maven: retrieving the main module version from a sub-module, but I can't figure out how to apply the answer. I'm trying this on Maven 3.6.3. I've posted the repository this can be played around with at this GitHub project
I have a top-level project:
<groupId>com.vps</groupId>
<artifactId>main-module</artifactId>
<version>5.0</version>
<packaging>pom</packaging>
There is another multi-module project that needs to be parented by this top-level project, and it has independent versioning from the top-level project.
The projects are not expected to be in the same repository, and are generally released independently of each other.
I want to declare a property that I can further use to refer to the version of this top-level project parent (say to pull in artifacts with the correct version):
<artifactId>auxiliary</artifactId>
<version>1.0</version>
<parent>
<groupId>com.vps</groupId>
<artifactId>main-module</artifactId>
<version>5.0</version>
</parent>
<properties>
<main.version>${project.parent.version}</main.version>
</properties>
<modules><module>corelib</module></modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vps</groupId>
<artifactId>main-module-1</artifactId>
<version>${main.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Now, the sub-module is to pull and use the dependency:
<parent>
<groupId>com.vps</groupId>
<artifactId>auxiliary</artifactId>
<version>1.0</version>
</parent>
<artifactId>corelib</artifactId>
<properties>
<!-- this doesn't work
<main.version>${project.parent.parent.version}</main.version>
-->
</properties>
<dependencies>
<dependency>
<groupId>com.vps</groupId>
<artifactId>main-module-1</artifactId>
</dependency>
</dependencies>
If I set main.version as a reference to ${project.parent.version} in the auxiliary POM, compilation of corelib fails because it tries to pull com.vps:main-module-1:1.0, which doesn't exist. I guess this is because the properties are resolved based on the effective POM being processed at the moment, and from there, the ${project.parent.version} is the version of corelib's parent.
If I override main.version in the corelib sub-module as ${project.parent.parent.version}, I get an error saying that effective version computed for com.vps:main-module-1 is '${project.parent.parent.version}', and is invalid. I guess this means that the property cannot be resolved all together, but I can't quite understand why.
So, how do I reasonably (i.e. without hardcoding the top-level in both the parent definition and another property) refer to that top-level version value from descendant submodules?

How to turn off transitive dependencies for maven projects?

I have come across the JIRA post that gives a solution as including exclusion tag in each dependency tag of POM.
But I have large number of projects and each project has huge number of dependency tags. It's not feasible to include this <exclusion> in each of the dependency tags.
Question: Is there a way to globally switch off the importing of transitive dependencies in maven?
In Maven you cannot switch off transitive dependencies for all declared dependencies in a single way, as stated by official documentation
Why exclusions are made on a per-dependency basis, rather than at the POM level
This is mainly done to be sure the dependency graph is predictable, and to keep inheritance effects from excluding a dependency that should not be excluded. If you get to the method of last resort and have to put in an exclusion, you should be absolutely certain which of your dependencies is bringing in that unwanted transitive dependency.
Indeed, since Maven 3.2.1 you can specify wildcards to exclude all transitive dependencies for a specific dependency, but that's still per dependency and not global.
What you actually would like to have something like the following per each and every dependency in each and every pom (!!):
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
Although this is not advisable since it may easily (and negatively) affect maintainability of concerned projects, a possible solution would be to have a common parent POM for all of the concerned projects, so that each pom would declare:
<parent>
<groupId>com.sample</groupId>
<artifactId>projects-governance</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
Then, in the concerned parent POM you would have:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<!-- for each and every foreseen dependency of children poms -->
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Note the dependencyManagement section, here we are saying: to all children POMs, whenever you use the concerned dependencies I declare, for this groupId and this artifacId by default this version and this exclusions will be applied.
The main advantages of this solution is that you centralize this mechanism/management so that at least you don't have to touch each and every POM (except the change concerning the new parent).
However, you would still need to list in the parent POM all the dependencies used by all the projects and apply a wildcard exclusion for all of them.
To get a list of all dependencies per project, you can probably go for a manual approach (open each and every POM!) or run on each project the following:
mvn dependency:list -DexcludeTransitive=true -DoutputFile=dependencies.txt -DappendOutput=true
The Maven Dependency Plugin would then write in the specified dependencies.txt file the declared dependencies (in the format groupId:artifactId:packaging:version:scope) of the concerned project. Note the last parameter, appendOutput, could be helpful to write at the end of the same file in order to keep them centralized for further processing (removing duplicates, moving them to the new parent pom).
To apply wildcards to all declared dependencies, a quick hint is to simply replace (with any text editor or via shell scripting) the following tokens:
</version>
</dependency>
By the following ones:
</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
Then save the file. And automatically you would have in a quite safe manner applied wildcard exclusions to all dependencies.
Update by OP: Finally we decided not to do this and instead, solve the original problem by using dependency tree command to generate reports of the newly added/removed dependencies for each project and broadcast it.
Even though I'm not sure why would you want such a mechanism, and I don't recommend that, only exclude transitive dependencies that you actually don't want where the dependencies which depends on them can some how run without them.
The last point is very important those transitive dependencies are needed by your dependencies in order to work probably.
So despite all the above here you go, there is a plugin from Apache Maven called Apache Maven Enforcer Plugin, one of the built in rules it has is Ban Transitive Dependencies

maven pom.xml dependencies order vs classpath/build path order

I am trying to understand the connection between the dependencies in a project's pom.xml file and the order of the java classpath/build path (my question is also regarding the inheritance of poms).
So far I wasn't able to find a detailed step-by-step explanation.
I have noticed for sure that it's not "the same", meaning, sometimes dependencies I have in my pom.xml will not appear in the build path in eclipse or will not be in the same order(after committing mvn eclipse:eclipse -$someflag) .
Let's assume for example I have the following Parent pom:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>SOME_GROUP_ID</groupId>
<artifactId>PARENT</artifactId>
<version>SOME_VERSION</version>
<name>${project.groupId}:${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>SOME_OTHER_ARTIFACT1</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<modules>
<module>CHILD</module>
</modules>
</project>
and that some other project's pom.xml inherits it:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>SOME_GROUP_ID</groupId>
<artifactId>PARENT</artifactId>
<version>SOME_VERSION</version>
</parent>
<artifactId>CHILD</artifactId>
<name>${project.groupId}:${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>SOME_OTHER_ARTIFACT2</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
My questions are: If I now run mvn eclipse:eclipse -$someflag on CHILD project:
Should the build path for CHILD project contain: PARENT, SOME_OTHER_ARTIFACT1, SOME_OTHER_ARTIFACT2 for sure? not for sure? when and why one of them should/shouldn't appear in the build path?
Should the classpath file for CHILD project contain: PARENT, SOME_OTHER_ARTIFACT1, SOME_OTHER_ARTIFACT2 for sure? not for sure? when and why one of them should/shouldn't appear in the build path?
Is it related to the flag (i.e $someflag) that was used when running mvn eclipse:eclipse?
Should the jars in the library appear also in the order of the dependencies in the project that is being initialized? i.e PARENT, SOME_OTHER_ARTIFACT1, SOME_OTHER_ARTIFACT2 (from top to bottom) necessarily? When and why should the order be different?
Thank you
Re "my question is also regarding the inheritance of poms"
See Maven: The Complete Reference, Project Inheritance:
You can avoid repeating yourself if your projects make use of inheritance via the parent element. When a project specifies a parent, it inherits the information in the parent project’s POM. It can then override and add to the values specified in this parent POM.
... and Multi-module vs. Inheritance:
There is a difference between inheriting from a parent project and being managed by a multimodule project. A parent project is one that passes its values to its children. A multimodule project simply manages a group of other subprojects or modules.

Maven cannot resolve a jar which I can see on the repository

I specify wicket version 1.5-RC7 in my pom.xml. When I do a mvn install it complains about: The following artifacts could not be resolved: org.apache.wicket:wicket:jar:1.5-RC7, javax.transaction:jta:jar:1.0.1B. So I try searching for the javax.transaction.jta-1.0.1B.jar on mvnrepository.com, and I am able to find it. Why does maven tell me it can't resolve avax.transaction:jta:jar:1.0.1B?
My pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/maven-v4_0_0.xsd">
…
<repositories>
<repository>
<id>mvnrepository</id>
<url>http://repo1.maven.org/maven2</url>
</repository>
</repositories>
<dependencies>
<!-- WICKET DEPENDENCIES -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-extensions</artifactId>
<version>${wicket.version}</version>
</dependency>
…
</dependencies>
</build>
<properties>
<wicket.version>1.5-RC7</wicket.version>
...
</properties>
</project>
First, http://repo1.maven.org/maven2 is the default one that Maven will lookup. You don't need to declare it again.
Can you check, when you build, which server your Maven is trying to connect? You should see something like Downloading: http://whatever.com/path/to/dependencies.pom.
I have just checked in maven central repo, there is no org.apache.wicket:wicket:1.5-RC7. You have better to check if you have declared the correct dependency
For JTA, it is a bit tricky. For quite some Java spec JARs, because of licensing issue, the actual JAR is not available in the public central Maven repo. If you look at http://search.maven.org/#artifactdetails|javax.transaction|jta|1.0.1B|jar , you will see it only contains POM, but not the JAR.
There are some ways to solve:
If you have a Maven repo in your own company, consider getting the JAR from Sun/Oracle, and deploy it yourself
For JTA spec itself, JAR is available for newer version (1.1) . Check if it is fine for you to use to latter spec
Switch to use Geromino spec. It should be compatible. http://search.maven.org/#search|gav|1|g%3A%22geronimo-spec%22%20AND%20a%3A%22geronimo-spec-jta%22
Edit
I have missed the wicket 1.5-RC7 in my previous search. Sorry. After looking into the POM, it seems that it is not a JAR POM. org.apache.wicket:wicket:1.5-RC7 is of type POM, in which declares dependency to wicket-core artifact.
You have two ways to do:
Change your dependency to point to wicket-core (and maybe other wicket modules) instead of wicket.
Change your dependency declaration to have <type>pom</type> (because default is jar)
I am not familiar with Wicket, but I believe method 1 is preferred.
Check your ~/.m2/settings.xml, I'm guessing you have an internal company (Nexus) repo mirror/proxy setting avoiding you fetching from internet -- and this mirror is stale.
If this is the case there are two common way to fix it: fix your internal Nexus repo so it's up to date, or bypass the Nexus repo so you fetch from the internet
I had faced this issue just now and resolved it. I have seen lot of questions in stack overflow related to this . Since my resolution was slightly different I am posting this answer. .
Issue :-Failed to execute goal on project Apigee-Edge-deploy-plugin: Could not resolve dependencies for project io.apigee.build-tools.enterprise4g:Apigee-Edge-deploy-plugin:maven-plugin:1.0.0: The following artifacts could not be resolved:
Root Cause:- The Repo had the dependency jars mentioned in the project. But the dependencies in turn had other dependencies which was not present in the repo and caused this issue. I added exclusion to the dependency and it worked.
eg:-
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-metadata</artifactId>
<version>1.3</version>
<type>jar</type>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>woden</artifactId>
<groupId>org.apache.woden</groupId>
</exclusion>
</exclusions>
</dependency>
Reference:-
Also checkout the very good article on maven dependencies and exclusion

Maven internal library pom version management

Are there any tools and/or best practices to help with managing a large set of internal libraries versions across many dependent projects. Allow me to elabore,
Say you have products A, B, C.
These products depend on libraries X, Y, Z, and there are dependencies within those as well.
In this world, we like to keep all versions on the latest released version of all dependencies (no snapshot dependencies except in working copies). This allows us to release the product at any time and force all projects to be run in CI (Hudson).
The issue is in keeping the pom.xml's all up-to-date. Currently, we use a custom maven plugin that, as part of each release, searches our SCM for pom.xml's that depend on the project being released and updates it. This is similar to the versions-maven-plugin except that you don't need a working copy of each project to do it.
There has got to be a better way. What do other teams do about many shared libraries across many projects? What is the best way to organize this? Multi-module works in some cases, but most of our libraries are fairly independent and used by too many other projects to (a) decide which multi-module it would belog to and (b) the hierarchy that would work for this.
managing dependencies in Maven works fine with dependencyManagement - I think you are familiar with it. You can outsource this dependencyManagement to a dedicated POM: a so called BOM POM (see http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html).
In your case this BOM POM might be shared by your products A, B and C. Due to that fact you should define a Maven project just containing this BOM POM with all the dependency management for thirdparty software X, Y and Z. This project can be released and you are able to add a dependency on your BOM POM with the scope import.
Your BOM POM:
<project>
<groupId>com.acme</groupId>
<artifactId>my-thirdparty-bom-pom</artifactId>
<version>1.0-SNAPSHOT</version>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>X</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>...</groupId>
<artifactId>Y</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>...</groupId>
<artifactId>Z</artifactId>
<version>...</version>
</dependency>
</dependencies>
<dependencyManagement>
...
</project>
Sample import for project A
<project>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>my-thirdparty-bom-pom</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>import</scope>
<dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>Y</artifactId>
<!-- the version is managed by the thirdparty bom imported above -->
</dependency>
</dependencies>
...
</project>
The closest thing is to use Dependency Version Ranges and then in a profile override your pom's repositories changing snapshots to false, making sure to include your profile during release with "-P".
<dependency>
<groupId>a</groupId>
<artifactId>a</artifactId>
<version>[3.8,4.0)</version>
</dependency>
...
<profiles>
<profile>
<id>your-release</id>
<repositories>
<repository>
...
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</profile>
<profiles>
Another pattern is the "bom" whereby you create a pom (packaging: pom) that declares a list of dependencies to make management easier (less to change).

Resources