Maven POM file: any rule on ordering of elements and sections? - maven

Concerning the pom.xml Maven file:
Is there any specific rule to apply to the ordering of declared sections?
Does it have any importance or impact on the build?
Shall I follow any official convention?

Although in most of the cases it is irrevant whether one section is declared before another, readeabilty could be indeed impacted when choosing a weird layout (e.g. Maven coordinates at the end).
But that's not the most important point, because yes, ordering of certain elements can impact your build.
Order of plugin declarations
The order of plugin sections wihtin the build/plugins section may be important. Since Maven 3.0.3 (MNG-2258), different plugin executions attached to the same Maven phase will be invoked in their order of declaration in the pom.xml file, after any execution attached via default bindings. That is, ordering is important in this case, since it may affect the behavior of the build.
Order of dependency declarations
Additionally, also order of dependency declarations within the dependencies section may affect your build towards Dependency Mediation, that is, the first declared dependency wins in case of conflict against a transitive dependency. So, once again, ordering is important in certain cases.
Note that if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.8 it was not defined which one would win, but since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins.
As a rule of thump: declare first the dependencies you directly reference in your code (that is, as import statements).
Order of module declaration
Although not relevant in most of the case, because (the) other important rules applies before, Maven will also respect the order of declaration of module element within the modules section during a multi-module build as last decision point. The reactor mechanism will in fact:
The following relationships are honoured when sorting projects:
a project dependency on another module in the build
a plugin declaration where the plugin is another modules in the build
a plugin dependency on another module in the build
a build extension declaration on another module in the build
the order declared in the element (if no other rule applies)
Note: bold added here.
Standard layout
Last but not least, although ordering is not important for other sections of the pom.xml file, good habit is to follow the official Maven recommendations:
The team has voted during the end of June 2008 to follow a specific POM convention to ordering POM elements.
As a simplified version, follow this order of declaration:
<project>
<modelVersion/>
<parent/>
<groupId/>
<artifactId/>
<version/>
<packaging/>
<properties/>
<dependencyManagement/>
<dependencies/>
<build/>
<reporting/>
<profiles/>
</project>
As a final note, the sortpom-maven-plugin can also be used to automatically apply this standard ordering, simply invoking the following on the concerned pom.xml file:
mvn com.github.ekryd.sortpom:sortpom-maven-plugin:2.5.0:sort \
-Dsort.keepBlankLines -Dsort.predefinedSortOrder=recommended_2008_06
Also note, the exceptions above are not handled, but documented by the plugin as special cases where indeed ordering may affect your build.
For further reading:
Official Maven doc: Plugin Bindings
Official Maven doc: Dependency Mediation
Official Maven doc: Maven Code Style And Code Conventions

Related

Maven: ensure same major parent pom version in multi-project development

Our team has multiple projects; most projects are just libraries. Let's assume for simplicity that the libraries don't depend on each other and there is a single project that uses them, e.g.:
Project Main:
Project Lib-A:
X (3rd-party library)
Project Lib-B:
X (3rd-party library)
To avoid surprises in 'Main', we'd like to make sure that all our own projects are using the same versions of the 3rd-party libraries, so that e.g. both 'Lib-A' and 'Lib-B' are built and tested with the same version of library X.
To achieve this we use a parent pom with <dependencyManagement> section detailing the versions of all relevant 3rd-party libraries and also their transitive dependencies. This parent pom is inherited by all the projects, i.e. 'Main', 'Lib-A', and 'Lib-B' from the above example. Then each child pom would only use <dependency> without specifying any version. We also have maven enforcer plugin's dependencyConvergence rule to make sure we have not missed any library conflict in any of our projects.
The problem: increasing the version of X: a developer of 'Lib-A' increases a version of X from 1.0 to 2.0. So he changes X's version in the parent pom, increases the version of parent, releases the parent pom, and notifies guys from 'Main' that they should now use a new parent. The situation becomes like this:
Main - inherits from Parent:2.0 and depends on:
Lib-A:2.0 - inherits from Parent 2.0 and depends on X:2.0
Lib-B:1.0 - inherits from Parent 1.0 and depends on X:1.0
X:2.0 (taken from Parent:2.0 <dependencyManagement> section)
Everything, including 'Main', builds fine, 'maven enforcer plugin' does not detect any conflict because the version of X is clearly specified in the Parent:2.0 from which 'Main' inherits. So we release 'Main'.
Ooops.... Lib-B has never been built with X:2.0. It has great unit tests that would uncover the problem, but we never tried this. We forgot to update Lib-B, try it with X:2.0 and release it. Still 'Main' has been built without problems and maven enforcer plugin has never complained.
Question: we need maven to detect that there are dependencies that inherit from the same artifact but different major versions and fail the build.
In our case the build had to fail since 'Main' and 'Lib-A' inherit from Parent:2.0, but 'Lib-B' inherits from Parent:1.0.
My solution so far (a hack): in addition to inheriting, add an explicit dependency on the parent pom to all out projects (i.e. 'Main', 'Lib-A', and 'Lib-B'):
<dependency>
<artifactId>Parent</artifactId>
<type>pom</type>
<version>${project.parent.version}</version>
</dependency>
Then use <bannedDependencies> rule of maven enforcer plugin to ban other major Parent versions (we could also use its <dependencyConvergence/> rule if we want to fail even on minor Parent version conflicts).
Is there a less hacky and cumbersome way to fail on conflicting major versions of parent pom?May be our entire approach to managing maven dependencies is wrong, what is the recommended way then?
Update:
Tried writing my own rule for maven-enforcer-plugin as suggested by #JF Mayer and described here, before giving up. Reasons:
First, the parent pom information is not available from the dependencies, at least not from the nodes built by maven's DependencyGraphBuilder
OK, I've added my parent poms as explicit dependencies to the children and tried to use this DependencyGraphBuilder to detect dependencies on the parent with different major versions. No way! As could be seen with mvn dependency:tree that also uses this class, DependencyGraphBuilder does not provide all the dependencies so it can't be used to detect dependencies conflicts. That's why the <dependencyConvergence> maven enforcer rule is using a super-deprecated DefaultDependencyTreeBuilder that has been even deleted from the GitHub and everywhere else - not a good choice for a trouble-free custom solution.
For completeness, my own poor-man's solution:
Add an explicit dependency of type pom to the parent to every project so that maven-enforcer-plugin's <dependencyConvergence> rule would detect conflicting parent versions. No big deal with this one as we only add this section once and forget about it:
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>${project.parent.artifactId}</artifactId>
<version>${project.parent.version}</version>
<type>pom</type>
</dependency>
<dependencyConvergence> will fail a build on 'Main' even on 'increment' differences in the parent versions, e.g. 1.0.1 and 1.0.2. In this case, the developer of 'Main' can decide that it's OK to build it despite the parent version conflict, because it's insignificant (this was my original question). So he builds 'Main' with some special profile that excludes the dependency on the parent: mvn -P I-know-what-I-am-doing deploy.
I am not very happy with this solution because of the step 2 that requires the developers of 'Main' to build it with a special profile in case of a parent versions conflict. I'd prefer a solution that always fails on major parent version conflicts but ignores insignificant differences in the parent pom versions automatically, I just don't know how to achieve this.
I think what you are looking for is Reactor Module Convergence enforcer:
https://maven.apache.org/enforcer/enforcer-rules/reactorModuleConvergence.html
Its not the same as the dependency convergence rule.

Is it possible to force a Maven plugin to be included in a project from a dependency of that project?

I have three Java projects. The first is an application, com.foo:foo-application:1.0.0, and the second is a module used as a dependency to that application, com.foo:foo-framework:1.0.0. The third is a Maven plugin authored by our team, com.foo:foo-plugin:1.0.0.
My intention is that any project, e.g. foo-application, which uses classes available in foo-framework must also validate that it has used those classes correctly, where said validation is enforced by foo-plugin.
Is there a way to enforce this behaviour within foo-framework's POM.xml, whereby any Maven module which declares it as a dependency in its own POM will have foo-plugin executed as part of its build lifecycle?
No (at least no way that I'm aware of).
when you declare a dependency on something, youre declaring a dependency on its output artifacts (and transitively their dependencies as optionally described in that artifact's pom.xml file). There's no place in a pom file to force anything on the build importing it - the build importing it may not even be a maven build.
it appears you may be able to do something similar via other tools though - for example checkstyle supports discovering rules from dependencies on the classpath (not exactly what you want and depends on users of your library running checkstyle configured just right)

Installing BOM before Maven tries to resolves it

Is there a way to install a BOM as part of maven invocation before maven tries
to resolve it. See related questions for a normal dependency
Install local jar dependency as part of the lifecycle, before Maven attempts to resolve it
Is there are way to install maven dependencies before maven attempts to resolve them?
I have tried to run a plugin in validate phase, but maven always resolved the
bom first be it a import scope bom or used as a parent bom.
About BOM: http://www.baeldung.com/spring-maven-bom
The expected usage of maven BOM is within the dependencyManagement section of a pom.xml.
Maven documentation states:
Other projects that wish to use the library should import this pom into the dependencyManagement section of their pom. (Please refer to Introduction to the Dependency Mechanism)
In a multi-module project you would usually have a dependencyManagement section with the parent pom only.
Also, just for clarification: The bom is NOT causing dependencies to the artifacts indicated therein. It is merely indicating the versions of the "ingredients" that are intended to be used together (for dependencies that are composed of several artifacts expected to be used together) in case a dependency is added somewhere in a related pom such dependencyManagement applies to.
With such setup maven will resolve the bom at time of processing dependencyManagement section. This is time of evaluating the surrounding pom.xml (or any referencing sub-module). The bom is then added to the local repository like any other dependency.
So, under normal circumstances there is no need for "fetching the bom from the net and installing it into the local repository".
Now, why would a bom artifact not be available at the time a maven call is being started?
The artifact source (repository) is not accessible
Then, downloading the artifact and providing it into local repository would be the way to go.
The artifact version is not known before (or is decided at starting time, e.g. either be specifying a profile or indicating the version as a runtime parameter)
Then the dependency mechanisms of maven still would work as expected.
The bom artifact content (list of artifacts or respective versions) is not known before (e.g. as it is depending on outcome of some build step during the build run)
Then, you likely need to rethink your build process, as it looks like you are trying to force maven into something it is not designed to support. Likely, the "dynamic" part is intrinsic to your project and thus, the dynamic dependency really should be a sub-module within your (multi-module) project. But it is really hard to advise without more input on a specific use case.
While a specific artifact to be consumed within a build step might be provided late (by relying on lazy evaluation of dependencies), this will much more difficult with bom dependencies. As such are dependency management entities that need to be resolved before the first time any dependency needs to be resolved as maven can not known what artifacts are contained within the bom.
If actually there is a usecase that absolutely requires such bom to be provided dynamically, then the only chance is a two layer process, where the top layer is providing the bom and the lower layer is then using it. Please note, that such a solution absolutely needs two independent maven processes (so, NOT just a simple multi-module project) in order to get the resolution of the depenceManagement dependency deferred until it is known.

JBoss Maven BOMs and transitive dependencies

I'm trying to use a number of the BOMs in the org.jboss.bom group to bring in the API stacks that are compatible with EAP 6.3.0. My understanding is, that's what they're for. But when I reference them (using 'provided' or even 'compile' scope), the dependencies don't become transitively available. Given that "compile" scope is used on the items inside the BOMs, Maven's documentation of the dependency mechanism seems to indicate that those items should be added to the classpath of my project. Yet I'm getting undefined symbols for the classes that should be brought in.
For example, in project P, I'm including org.jboss.bom.wfk:jboss-javaee-6.0-with-spring:2.4.0-redhat-2 with 'provided' scope, yet org.springframework.context.ApplicationContext is undefined in P.
This is all happening in JBoss Dev Studio 8.1.0.GA, if that makes a difference.
I figured out the solution myself by reading the Maven Dependency documentation in more detail.
Here's my take-away: you cannot depend on the Eclipse m2e plugin to see you through the Maven dependency weeds. Know when/how to use the <dependencyManagement> section of the POM (and when not to use it). Know in particular the specific invocation Maven needs when you want to use a BOM: import the BOM in a <dependencyManagement> section with <type> of pom and <scope> of import, and then in the "regular" <dependencies> section (not <dependencyManagement>) specifically call out the sub-artifacts you need from the POM, but omit the version. (It's all spelled out here.)
The intent of the BOM is not to allow you to mass-import dependencies by referencing only the BOM artifact; rather, it's to make sure the versions of dependencies are the right ones, as defined by the BOM.
Do not assume that Maven allows you to express things in logically/mathematically reduced terms. Find out how to please the beast, and do not rely on a wizard to figure this out for you. Read the Maven docs in detail, find out the recipes and follow them exactly.

maven runtime scope but transitive dependencies have compile scope

Project A depends on project B with runtime scope.
Project B depends on project C with compile scope.
If code in project A calls a function in project C, I would expect mvn compile of project A to fail, but it does not.
What is the expected behavior?
I am using maven 3.0.4 with maven-compiler-plugin 2.5.1 and maven-dependency-plugin 2.5.
The maven documentation gives a slightly confusing until you understand it table.
To work out what the scope is you need to follow the following path of entries...
Start from the ultimate parent project and merge all the <dependencies> list. Do the same for <dependencyManagement>. When merging, the groupId:artifactId:type:classifier is the key, child poms which have dependencies with the same key overwrite whatever values they specify.
Now you need to apply the <dependencyManagement> to the <dependencies> list to fill in any blanks.
At this point we now know the dependencies of the current project. The scopes in this list correspond to the row you select from the table.
For each dependency in the list, you repeat the above process to compute the dependencies effective dependency list (yes including ths step too) and then the scope of these dependencies correspond with the column selection in the table.
Once you have worked out the transitive dependencies, and their scopes via the table, for each dependency, you then apply the current module's <dependencyManagement> overriding scope, version and exclusions as defined by <dependencyManagement> and there you have the effective transitive dependency list.
There are other more subtle effects which are there to retain existing behaviour where bugs have essentially become features, and version ranges can further confuse things, but above shoud give a god general understanding of the problem space

Resources